This is my first question, I need to add dynamically textViews to convertView that is returned in getChildView() method expandable, but I can not do in any way..
#Override
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
ViewHolderChild holder;
LayoutInflater inflater = context.getLayoutInflater();
if (convertView == null) {
convertView = inflater.inflate(R.layout.child_line, null);
holder = new ViewHolderChild();
holder.txNumeroSolicitacao = (TextView) convertView.findViewById(R.id.textViewNumeroSolicitacao);
convertView.setTag(holder);
} else {
holder = (ViewHolderChild) convertView.getTag();
}
holder.txNumeroSolicitacao.setText(String.valueOf(getChild(groupPosition,childPosition).getNumero()));
//if my log list isn't empty, I want add a textview dynamically to view
if(!getChild(groupPosition,childPosition).getLog().isEmpty()) {
holder.textViewResponse = new TextView(context);
RelativeLayout.LayoutParams alignParentLeft = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
alignParentLeft.addRule(RelativeLayout.ALIGN_PARENT_LEFT, RelativeLayout.TRUE);
holder.textViewResponse.setLayoutParams(alignParentLeft);
((ViewGroup) convertView).addView(holder.textViewResponse);
}
return convertView;
}
But I can not add the textView to convertView. The application always returns unexpected behaviour.
You might add the TextView in child_line.xml with android:visibility="gone", and set it's visibility in getChildView according to if the current line's bound object's log is empty.
Related
I want to open new activity that is different in each recyclerview item.
I have read and I do not need an image item here : How to open a different activity on recyclerView item onclick
This is my Adapter
public class B001Adapter extends RecyclerView.Adapter {
private Context context;
private LayoutInflater inflater;
List<B001Data> udata = Collections.emptyList();
public B001Adapter(Context context, List<B001Data> data) {
this.context = context;
inflater = LayoutInflater.from(context);
this.udata = data;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.datab001, parent, false);
MyHolder holder = new MyHolder(view);
return holder;
}
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
MyHolder myHolder = (MyHolder) holder;
final B001Data current = udata.get(position);
myHolder.device_name.setText(current.device_name);
myHolder.mac_address.setText(current.mac_address);
myHolder.status.setText("Status:" + String.valueOf(current.status));
}
#Override
public int getItemCount() {
return udata.size();
}
class MyHolder extends RecyclerView.ViewHolder {
TextView device_name, mac_address, status;
public MyHolder(View itemView) {
super(itemView);
context = itemView.getContext();
device_name = (TextView) itemView.findViewById(R.id.txt_device_name);
mac_address = (TextView) itemView.findViewById(R.id.txt_mac_address);
status = (TextView) itemView.findViewById(R.id.txt_status);
}
public void onClick(AdapterView<?> parent, View view, int position {
final Intent intent;
switch (getAdapterPosition()){
case 0:
intent = new Intent(context, MainActivity.class);
break;
case 1:
intent = new Intent(context, B001FacilityM.class);
break;
case 2:
intent = new Intent(context, B001HRD.class);
break;
default:
intent = new Intent(context, B001home.class);
break;
}
context.startActivity(intent);
}
}
}
I use volley to get Json data displayed on the recyclerView. Looking for your advice. Thanks
First You Should assign id to layout file (R.layout.datab001),
find out id using findViewsById in MyHolder() constructor
and then set onClickListener to layout like myHolder.layout.setOnClickListener(....);
in onBindViewHolder().
or check other answer
RecyclerView onClick
I have been working on an app that requires me to get information such as a Place Name and a PLace Photo from google PLaces Api and set it into a RecyclerView. I am stuck because I managed to get the code to work with no errors but the RecyclerView is empty. What is wrong with my code?
I am stuck because I don't know where the problem is. When I run the code, all the fetchs work and the tags show up in the Log so I am completely lost. My first thought is that I am displaying the code wrong but then I have no recourse to step forward and change it to something else because I am not sure if it would be better or worse.
This is the Fragment for the RecyclerView Item:
public class VenueList extends Fragment{
ArrayList<VenueItem> vIL = new ArrayList<>();
private PlacesClient placesClient;
private Context contextForPlaces;
place ids for the places I am currently using
String[] clubs = {"ChIJO_uSYKNZwokRAC7RLeB0oZ8", "ChIJAQBEylJYwokRLbnrAchQImk",
"ChIJU_26rfpYwokRTNf2K1-7p8E", "ChIJ38hxfnhZwokRx1HSFLj790w", "ChIJBwnlGrdZwokRpf61pMm860c"
, "ChIJpSIzqrhZwokR1KnVMoVty_g", "ChIJMRV7375ZwokRAfltF6Y-wYw", "ChIJYabdHPhYwokRPmAV8GtM3gs",
"ChIJi2dSjQRZwokRuXUKcv4riVc", "ChIJKaKVI79ZwokRN8WicODOIAw", "ChIJwXI8Fb5ZwokRr4JjG4HxSP8",
"ChIJ6bU_E4ZZwokR2ZDbY_IhhrI"};
#Override
public void onAttach(Context context) {
super.onAttach(context);
contextForPlaces = context;
}
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.menu_venue, container, false);
RecyclerView vRV = view.findViewById(R.id.view_venue);
List<Place.Field> placeFields = Arrays.asList(Place.Field.NAME, Place.Field.PHOTO_METADATAS);
if (!Places.isInitialized()) {
Places.initialize(contextForPlaces, "AIzaSyCKGd3fqmtsDklRGMhnkuIy1GS-j6gRBh8");}
placesClient = Places.createClient(contextForPlaces);
vRV.setHasFixedSize(true);
RecyclerView.LayoutManager vLM = new LinearLayoutManager(this.getActivity());
RecyclerView.Adapter vAdapter = new VenueAdapter(vIL);
// run through each photo to make sure it has a place attached to it then insert each photo and place into the vIL
//createBitmap for fetchPhoto
for (String club : clubs) {
FetchPlaceRequest request = FetchPlaceRequest.newInstance(club, placeFields);
placesClient.fetchPlace(request).addOnSuccessListener((response) -> {
Place place = response.getPlace();
PhotoMetadata photoMetadata = place.getPhotoMetadatas().get(0);
String attributions = photoMetadata.getAttributions();
FetchPhotoRequest photoRequest = FetchPhotoRequest.builder(photoMetadata).setMaxHeight(200).build();
placesClient.fetchPhoto(photoRequest).addOnSuccessListener((fetchPhotoResponse) -> {
Bitmap bitmap = fetchPhotoResponse.getBitmap();
vIL.add(new VenueItem(/*Photo*/bitmap, place/*Name*/));
Log.i(TAG, "Photo Should Be Up: ");
}).addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
int statusCode = apiException.getStatusCode();
// Handle error with given status code.
Log.e(TAG, "Place not found: " + exception.getMessage());
}
});
Log.i(TAG, "Place found: " + place.getName());
}).addOnFailureListener((exception) -> {
if (exception instanceof ApiException) {
ApiException apiException = (ApiException) exception;
int statusCode = apiException.getStatusCode();
// Handle error with given status code.
Log.e(TAG, "Place not found: " + exception.getMessage());
}
});
}
vRV.setLayoutManager(vLM);
vRV.setAdapter(vAdapter);
return view;
}
This is the part of the RecyclerView Adapter I changed. I used to be a getResourse for the image because the image was from the drawable folder
public void onBindViewHolder(#NonNull VenueViewHolder venueViewHolder, int i) {
VenueItem currentItem = vIAL.get(i);
if(currentItem.getVenueImageResource() == null){
venueViewHolder.vIV.setImageResource(R.drawable.ic_android);
}else
venueViewHolder.vIV.setImageBitmap(currentItem.getVenueImageResource());
venueViewHolder.vTV.setText((CharSequence) currentItem.getVenueDescription());
}
The Item itself which I also had to change a bit from its original. I made the string a Place and the int a Bitmap. I thought that would work.
public class VenueItem {
private Bitmap venueImageResource;
private Place venueDescription;
public VenueItem(Bitmap vIR, Place description) {
venueImageResource = vIR;
venueDescription = description;
}
public Bitmap getVenueImageResource() {
return venueImageResource;
}
public Place getVenueDescription() {
return venueDescription;
}
}
I want to be able to request a place name and a photo of the place using the placesClient and precent it in the for of a RecyclerView. I know the place Ids are correct because the Log returns the names of all the places. But they do not show up on the RecyclerView
I figured out the answer myself.
vRV.setLayoutManager(vLM);
vRV.setAdapter(vAdapter);
I just had to put these two lines into the for loop under the list item so that each item could escape before meing erased
I have an issue with my TableView and its items. I have created a small Dialog window to display warnings about my app, and inside the Dialog I have a TableView which displays the name of the warning and some information about it upon clicking on a button.
I have created a WarningUtil class (Singleton pattern) just to open / close the Dialog. The relevant code follows.
The constructor of the WarningUtil class (called once only) :
private WarningUtil(RootCtrl rootCtrl) {
this.rootCtrl = rootCtrl;
warnings = new HashMap<>();
setupWarningCallbacks(); // not relevant
setupTable();
setupColumns(); // not relevant
setupDialog();
}
The function managing the construction of the Dialog :
private void setupTable() {
// create the content pane
content = new AnchorPane(); // class variable - reference needed for further uses
content.setPrefSize(480, 240);
// create the root nodes of the view (table + 2 columns)
warningTable = new TableView<>(); // class variable - reference needed for further uses
warnDescriptionCol = new PTableColumn<>(); // class variable - reference needed for further uses
warnDetailsCol = new PTableColumn<>(); // class variable - reference needed for further uses
// settings anchors to keep the ration between dialog <-> table
AnchorPane.setBottomAnchor(warningTable, 15.0);
AnchorPane.setTopAnchor(warningTable, 15.0);
AnchorPane.setLeftAnchor(warningTable, 15.0);
AnchorPane.setRightAnchor(warningTable, 15.0);
// setting up the columns
warnDescriptionCol.setText(i18n("label.desc"));
warnDetailsCol.setText(i18n("label.details"));
warnDescriptionCol.setPercentageWidth(0.7);
warnDetailsCol.setPercentageWidth(0.3);
warnDescriptionCol.setResizable(false);
warnDetailsCol.setResizable(false);
// adding nodes to containers
warningTable.getColumns().addAll(warnDescriptionCol, warnDetailsCol);
content.getChildren().add(warningTable);
}
The function used to create the Dialog and set the content :
private void setupDialog() {
// creation and saving of the dialog in a variable reused later
warningDialog = DialogFactory.getInstance(rootCtrl.getPrimaryStage()).createWarningDialog();
warningDialog.getDialogPane().setContent(content);
warningDialog.getDialogPane().getScene().getWindow().sizeToScene();
}
// The DialogFactory function creating the dialog
public Dialog createWarningDialog(){
CustomDialog dialog = new CustomDialog(rootStage);
dialog.setTitle(i18n("warning.description"));
ButtonType cancelBt = new ButtonType(i18n("button.close"), ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().add(cancelBt);
return dialog.setupLayout();
}
The Main class is in charge of loading the warnings (stored in a .json file and deserialized upon starting the app). For now, the file only contains one entry.
When I click on my Warning button, the following function is called :
public void showWarnings() {
warningTable.getItems().clear(); // BP
warningTable.setItems(FXCollections.observableArrayList(warnings.values()));
warningDialog.showAndWait();
}
What happens is the following : When I have only one entry in my .json file, the first time I click on the button, only one warning is shown. If I click a second time, a second entry appears (the same) which should not be possible because of the following reasons :
Logic constraint : warnings.values() comes from an HashMap where the key is the type of the warning (WarningType class) > Not possible to have two identical keys
Debugging : When I set a breakpoint at "//BP", I clearly see that the warningTable has one item, and after clear the number of items is zero
Debugging : Still with the same breakpoint, I also check that warnings.values() has only one item, which is the case
After five clicks on the button, the Dialog clearly shows something is bugging.
More surprisingly, when I add a second warning (different from the first one, another type), the problem does not occur : No duplicates, warnings are correctly displayed and no matter how many times I open the window.
My question is : Could that be that the way I am creating this warning dialog leads to uncommon errors ? If so, why isn't it the case with two warnings ?
EDIT Include of the cellFactories / cellValueFactories
private void setupColumns() {
warnDescriptionCol.setCellFactory(new Callback<TableColumn<CustomWarning, String>, TableCell<CustomWarning, String>>() {
#Override
public TableCell<CustomWarning, String> call(TableColumn<CustomWarning, String> param) {
TableCell<CustomWarning, String> cell = new TableCell<CustomWarning, String>() {
#Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Label label = new Label(item);
setGraphic(label);
}
}
};
return cell;
}
});
warnDetailsCol.setCellFactory(new Callback<TableColumn<CustomWarning, CustomWarning>, TableCell<CustomWarning, CustomWarning>>() {
#Override
public TableCell<CustomWarning, CustomWarning> call(TableColumn<CustomWarning, CustomWarning> param) {
TableCell<CustomWarning, CustomWarning> cell = new TableCell<CustomWarning, CustomWarning>() {
#Override
protected void updateItem(CustomWarning item, boolean empty) {
super.updateItem(item, empty);
if (item != null) {
Button button = new Button(i18n("button.view"));
button.getStyleClass().add("save");
button.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
showWarning(item);
}
});
setGraphic(button);
}
}
};
return cell;
}
});
warnDescriptionCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomWarning, String>, ObservableValue<String>>() {
TableViewObjectWrapper<CustomWarning, String> wrapper = new TableViewObjectWrapper<CustomWarning, String>() {
#Override
public String getData() {
return getModel().getTitle();
}
};
#Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<CustomWarning, String> param) {
return new ReadOnlyObjectWrapper<>(wrapper.setModel(param.getValue()).getData());
}
});
warnDetailsCol.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<CustomWarning, CustomWarning>, ObservableValue<CustomWarning>>() {
TableViewObjectWrapper<CustomWarning, CustomWarning> wrapper = new TableViewObjectWrapper<CustomWarning, CustomWarning>() {
#Override
public CustomWarning getData() {
return getModel();
}
};
#Override
public ObservableValue<CustomWarning> call(TableColumn.CellDataFeatures<CustomWarning, CustomWarning> param) {
return new ReadOnlyObjectWrapper<>(wrapper.setModel(param.getValue()).getData());
}
});
}
You have to clear your cells in the cell factory if the cell is empty, as explained in the documentation:
It is very important that subclasses of Cell override the updateItem method properly, as failure to do so will lead to issues such as blank cells or cells with unexpected content appearing within them. Here is an example of how to properly override the updateItem method:
protected void updateItem(T item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
setGraphic(null);
} else {
setText(item.toString());
}
}
Note in this code sample two important points:
We call the super.updateItem(T, boolean) method. If this is not done, the item and empty properties are not correctly set, and you are likely to end up with graphical issues.
We test for the empty condition, and if true, we set the text and graphic properties to null. If we do not do this, it is almost guaranteed that end users will see graphical artifacts in cells unexpectedly.
Since the cells are reused, you have to clear the graphic if it has become empty, not just set it if it's not.
I want to change the list-view item background color without onitemclick() method. Because at first i've to check item data and based on that it will change the color . How should i do it ?
listView.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View view, int position,
long id) {
if(items.get(position).getSomething().equals(Something){
// If your condition fulfills then change background color
listView.getChildAt(position).setBackgroundColor(#55667788);
}
}
});
EDIT:
#Override
public View getView(final int position, View convertView, ViewGroup arg2) {
// TODO Auto-generated method stub
if (convertView == null) {
LayoutInflater inflater = context.getLayoutInflater();
convertView = inflater.inflate(R.layout.row_counter, null);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.name = (TextView) convertView.findViewById(R.id.tv_name);
viewHolder.number = (TextView) convertView
.findViewById(R.id.tv_number);
viewHolder.row = (TextView) convertView
.findViewById(R.id.rel_row);
convertView.setTag(viewHolder);
}
holder = (ViewHolder) convertView.getTag();
currentModel = list.get(position);
holder.name.setText(currentModel.getName());
holder.number.setText(currentModel.getNumber());
if(holder.name.equals("SOMETHING")){
holder.row.setBackgroundColor("#55667788");
}else{
holder.row.setBackgroundColor("#000000");
}
return convertView;
}
I have a navigation controller to show a list o item on table, then I need to touch an item a show the details of this item.
Here it's my code of how a fill the table:
public void SearchHotel (){
Hotel hotel = new Hotel();
var distribution = new HotelDistribution[]{new HotelDistribution(){ Adults = 1, Children = 0, ChildrenAges = new int[0]} };
var items = hotel.SearchHotels(Convert.ToDateTime("2013-08-08"),Convert.ToDateTime("2013-09-09 "),"(MIA)", distribution,"","","",0);
data = new List<DtoHotelinformation>();
foreach (var item in items)
{
DtoHotelinformation DtoHotelinformation = new DtoHotelinformation();
DtoHotelinformation.code = item.Code.ToString();
DtoHotelinformation.price = item.Price.ToString();
DtoHotelinformation.title = item.Name.ToString().ToTitleCase();
DtoHotelinformation.subtitle = item.Address.ToString();
DtoHotelinformation.rating = item.Rating.ToString();
DtoHotelinformation.imageUlr = item.ImageUrl;
data.Add(DtoHotelinformation);
}
hud.Hide(true);
hud.RemoveFromSuperview();
HotelSearchTable.Source = new HotelTableSource(data.ToArray());
HotelSearchTable.ReloadData();
}
Because I'm using storyboard to show the details view controller I have this code on my table source:
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
if (RowTouched != null) {
RowTouched (this, EventArgs.Empty);
}
tableView.DeselectRow (indexPath, true); // normal iOS behaviour is to remove the blue highlight
}
Back in to my viewcontroller I call the RowTouched to show the details controller like this:
public override void ViewDidAppear (bool animated) {
base.ViewDidAppear (animated);
SearchHotel ();
var source = new HotelTableSource(data.ToArray());
var detail = Storyboard.InstantiateViewController("HotelDetailScreen") as iPhoneHotelDetailViewController;
source.RowTouched += (sender, e) => {
this.NavigationController.PushViewController(detail, true);
};
HotelSearchTable.Source = source;
}
But I need to pass the information of the item touched on the table to show the details. I don't really don't know what do I have to do?
NOTE: I can't use PrepareForSegue because I don't have a segue between controllers.
Thanks in advance
If you want you can get a hold of your UINavigationController
from within your Row Selected event, inside of your Table Data Source.
From there you can push your new ViewController.
[indexPath.Row] in "Row_Selected" should tell you which element in your array or list, that the user has selected.
UINavigationController navcontroller =(UINavigationController)UIApplication.SharedApplication.Windows[0].RootViewController;
Passing data to an event handler is exatly what the EventArgs parameter is for.
Create a class that inherits from EventArgs and has properties for the data you need:
public class HotelSelectedEventARgs : EventArgs
{
public DTOHotelInformation HotelInfo { get; set; }
}
Then, when you call your handler in RowSelected, instead of passing an empty EventArgs, create an instance of your custom class and assign the selected data to the HotelInfo property.