I'm trying to implement StfalconImageViewer in my app using these links: here and here. this is my code:
View imageDetail = activity.getLayoutInflater().inflate(R.layout.chat_image_pager, container , false);
ImageView back = imageDetail.findViewById(R.id.back);
TextView totalImages = imageDetail.findViewById(R.id.totalImages);
TextView imagePosition = imageDetail.findViewById(R.id.mediaCounter);
TextView sentDate = imageDetail.findViewById(R.id.sentDate);
TextView sentBy = imageDetail.findViewById(R.id.sentBy);
TextView sentTime = imageDetail.findViewById(R.id.sentTime);
back.setOnClickListener(v -> {
//what should I write here???
});
StfalconImageViewer.Builder<ChatMessageBuilder> builder = new StfalconImageViewer.Builder<>
(activity,ChatImageData.imageMessages, (imageView, image) -> {
Glide.with(fragment)
.load(image.getMediaAddress())
.into(imageView);
});
//some other codes
builder
.withStartPosition(ChatMessageInterfaceFragment.imagePosition)
.withHiddenStatusBar(false)
.allowZooming(true)
.allowSwipeToDismiss(true)
.withImageChangeListener((position) -> {
//some codes
})
.withBackgroundColorResource(R.color.background_light)
.withTransitionFrom(messageImage)
.withOverlayView(imageDetail)
.show();
As you can see there is an Overlay named imageDetail and a button (in Overlay) named back which should close imageViewer and get me back to my RecyclerView but the problem is I can't really put a right code for this. Any help would be appreciated.
Ok after a long test and experiments finally found it. here is the code:
View imageDetail = activity.getLayoutInflater().inflate(R.layout.chat_image_pager, container , false);
ImageView back = imageDetail.findViewById(R.id.back);
TextView totalImages = imageDetail.findViewById(R.id.totalImages);
TextView imagePosition = imageDetail.findViewById(R.id.mediaCounter);
TextView sentDate = imageDetail.findViewById(R.id.sentDate);
TextView sentBy = imageDetail.findViewById(R.id.sentBy);
TextView sentTime = imageDetail.findViewById(R.id.sentTime);
StafalconImageViewer builder = new StfalconImageViewer.Builder<>
(activity,ChatImageData.imageMessages, (imageView, image) -> {
Glide.with(fragment)
.load(image.getMediaAddress())
.into(imageView);
});
//some other codes
builder
.withStartPosition(ChatMessageInterfaceFragment.imagePosition)
.withHiddenStatusBar(false)
.allowZooming(true)
.allowSwipeToDismiss(true)
.withImageChangeListener((position) -> {
//some codes
})
.withBackgroundColorResource(R.color.background_light)
.withTransitionFrom(messageImage)
.withOverlayView(imageDetail)
.show();
now our onClickListener works:
back.setOnClickListener(v -> {
builder.onDismiss();
});
If we use the base Class which mean StafalconImageViewer and not the
StafalconImageViewer.Builder, the onDismiss() method works fine!
Related
I'm working on Radio Buttons and I want each RadioButton to re-call the TextWatcher in every onClick to update my TextView but it doesn't work.
all of this code is inside a Fragment and I got only one Activity
RadioButton:
View.OnClickListener radio1Clicked = v ->{
radioButton1.addTextChangedListener(textWatcher); //error under textWatcher : Illegal forward reference
//More Operations Running here ... };
View.OnClickListener radio2Clicked = v ->{
radioButton2.addTextChangedListener(textWatcher)};//error under textWatcher: Illegal forward reference
//More Operations Running here ... };
View.OnClickListener radio3Clicked = v ->{
radioButton2.addTextChangedListener(textWatcher)};//error under textWatcher: Illegal forward reference
//More Operations Running here ... };
Text Watcher:
TextWatcher textWatcher= new TextWatcher(){
//Declarations and other stuff
// RadioButton1
if (radioButton1.isChecked()) {
basePrintable = 50;
calculatePcs = (int) (50 / sqIn);
iPieces.setText(String.valueOf(calculatePcs ));
if (!checker)//check Switch {
iPriceOut.setText("150.0");
} else if (checker) //re-check Switch{
iPriceOut.setText("50.0");
}
}
// RadioButton1
if (radioButton1.isChecked()) {
basePrintable = 50;
calculatePcs = (int) (50 / sqIn);
iPieces.setText(String.valueOf(calculatePcs ));
if (!checker)//check Switch {
iPriceOut.setText("150.0");
} else if (checker) //re-check Switch{
iPriceOut.setText("50.0");
}
}
// RadioButton2
if (radioButton1.isChecked()) {...}
// RadioButton3
if (radioButton1.isChecked()) {...}
basePcs = Integer.parseInt(iPieces.getText().toString());
baseSheet =
Integer.parseInt(iShit.getText().toString());
basePrice =
Double.parseDouble(iPriceOut.getText().toString());
}
I know it could be called cause I'm already doing it here: (and it works)
public void onCheckedChanged(CompoundButton switchInput, boolean isChecked) {
switchInput.addTextChangedListener(size);
if (!isChecked) {
switchInput.setText("...");
radioButton1.setText("...");
radioButton2.setText("...");
radioButton3.setText("...");
} else {
switchInput.setText("...");
radioButton1.setText("...");
radioButton2.setText("...");
radioButton3.setText("...");
}
}
I'm a complete noob and only following along Tutorials and stitching this app for myself. this is the last problem I have to solve cause everything else is more or less done.
Thanks for the Help
I think the problem is that you can't reference the object that was clicked inside, instead use the view that is passed
View.OnClickListener o1 = v ->{
iOpt1.addTextChangedListener(size); //error: Illegal Forward Reference
if (iOpt1.isChecked()) {
iOpt2.setChecked(false);
iOpt3.setChecked(false);
}
iOpt1.setChecked(true);
};
change to
View.OnClickListener o1 = v ->{
v.addTextChangedListener(size); <--change here //error: Illegal Forward Reference
if (v.isChecked()) { <--change here
iOpt2.setChecked(false);
iOpt3.setChecked(false);
}
v.setChecked(true);<--change here
};
using v as the view was clicked
I just needed to update or refresh the TextWatcher by re-assigning it's own content back to an EditText it was injected on, this will cause an update and will run the TextWatcher since basically it has been updated.
View.OnClickListener o1 = v ->{
if (iOpt1.isChecked()) {
iOpt2.setChecked(false);
iOpt3.setChecked(false);
}
iOpt1.setChecked(true);
//SOLUTION: save the value on where the **TextWatcher** is injected then re-assign the same value you saved
refesher = iLength.getText().toString();
iLength.setText(refesher);
//This will cause an update to the **TextWatcher** and will run the code again
};
TextWatcher size = new TextWatcher() {...}
Here's more Context
public class PrintFragment extends Fragment{
EditText iLength, iHeight;
RadioButton iOpt1, iOpt2, iOpt3;
String refresher;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
//inflate
iLength = V.findViewById(R.id.length);
iHeight = V.findViewById(R.id.height);
iOpt1 = V.findViewById(R.id.opt1);
iOpt2 = V.findViewById(R.id.opt2);
iOpt3 = V.findViewById(R.id.opt3);
iLength.addTextChangedListener(size);
iHeight.addTextChangedListener(size);
iOpt1.setOnClickListener(o1);
iOpt2.setOnClickListener(o2);
iOpt3.setOnClickListener(o3);
return;
}
View.OnClickListener o1 = v ->{
if (iOpt1.isChecked()) {
iOpt2.setChecked(false);
iOpt3.setChecked(false);
}
iOpt1.setChecked(true);
refesher = iLength.getText().toString();
iLength.setText(refesher);
};
TextWatcher size = new TextWatcher() {...}
}
I am trying to display data from a an array list but after the marker onclick
it only displays the last element in the array list in the material dialog box
DriverLocationDataManager gets all the data snapshots of the geopoints of the drivers in the database
after adding in all the driver data, i use the addMarker function which gets the geopoints and set the markers on the map.
//Init data manager
drivers = new ArrayList<>(0);
dataManager = new DriverLocationDataManager(this) {
#Override
public void onDataLoaded(List<Driver> data) {
if (data.isEmpty()) {
Snackbar.make(container, "Sorry!. UG Shuttle service is currently unavailable",
Snackbar.LENGTH_INDEFINITE).show();
} else {
drivers.addAll(data);
List<Marker> markers = addMarkers(data);
for (int i = 0; i < markers.size(); i++){
markers.get(i);
Driver driver = drivers.get(i);
map.setOnMarkerClickListener(marker -> {
// Get custom view
View v = getLayoutInflater().inflate(R.layout.driver_popup, null, false);
//Assign props
TextView username = v.findViewById(R.id.driver_username);
CircularImageView profile = v.findViewById(R.id.driver_profile);
ImageView status = v.findViewById(R.id.driver_status);
TextView shuttle = v.findViewById(R.id.driver_bus_number);
ViewGroup viewGroup = v.findViewById(R.id.group);
//Init props
Glide.with(getApplicationContext())
.load(driver.getProfile())
.apply(RequestOptions.circleCropTransform())
.apply(RequestOptions.placeholderOf(R.drawable.avatar_placeholder))
.apply(RequestOptions.errorOf(R.drawable.avatar_placeholder))
.apply(RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.AUTOMATIC))
.transition(withCrossFade())
.into(profile);
username.setText(driver.getDriver()); //Driver's username
shuttle.setText(driver.getCarNumber()); //Driver's car number
//Attach to dialog
Builder materialDialog = new Builder(HomeActivity.this)
.customView(v, true)
.negativeText("Dismiss")
.onPositive((dialog, which) -> {
dialog.dismiss();
enableTracking(marker);
})
.onNegative((dialog, which) -> dialog.dismiss());
if (driver.isStatus()) {
status.setImageResource(android.R.color.holo_green_light); //Online
//Enable tracking when driver is online
materialDialog.positiveText("Track")
.onPositive((dialog, which) -> {
dialog.dismiss();
enableTracking(marker);
});
} else {
//Tracking is disabled
status.setImageResource(android.R.color.holo_red_light); //Offline
}
materialDialog.build().show();
return true;
});
}
}
}
};
I invite you to read the official developer guide here. It explains how to properly use Dialogs, how to display a list in it, and even how to implement a custom view if you need one to display your list.
When my fragment is created it calls
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View layout=inflater.inflate(R.layout.fragment_item_fragment1, container, false);
populatePage();
return layout;
}
and within that calls the populatepage() method. Within that method a call to a webservice is made. I have verified that the data exits and everything runs without error.
public void populatePage(){
String globalKey = "key";
String url = "";
//shared preferences
SharedPreferences settings = getActivity().getSharedPreferences(sharedPreferences, 0);
final String SESSION_KEY = settings.getString("SESSION_KEY", "nothing is here");
String FILE_KEY = settings.getString("FILE_KEY", "");
String page = settings.getString("PAGE", "Part");
final String group = settings.getString("FRAG_1", "");
String record = settings.getString("RECORD", "");
//BUILD THE URL WE NEED
url = "https://url.com/"
//loading page
//Declare the headers and add the pairs
Headers header = new Headers();
header.add("X-SESSION-KEY", SESSION_KEY);
header.add("X-GLOBAL-KEY", globalKey);
//Layout for building upon
final LinearLayout ll = new LinearLayout(getActivity());
ll.setOrientation(LinearLayout.VERTICAL);
$.ajax(new AjaxOptions().url(url)
.type("GET")
.dataType("json")
.headers(header)
.contentType("application/json")
.context(getActivity()).success(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
JSONObject json = (JSONObject) params[0];
try {
Boolean session = json.getBoolean("valid");
if (session) {
JSONArray recordsArray = json.getJSONArray("field");
String groupName = ""; //we compare group to this before adding it as a preference since we dont want dupes
for (int i = 0; i < recordsArray.length(); i++) {
JSONObject record = recordsArray.getJSONObject(i);
//BIG MESSY IF STATEMENT TO PARSE DATA! HOORAY!
if (record.getString("group").equals(group)) {
if (record.getString("valueType").equals("Text")) {
TextView label = new TextView(getActivity());
label.setText(record.getString("label"));
label.setPadding(20, 20, 20, 0);
label.setTextSize(20);
label.setTypeface(null, Typeface.BOLD);
label.setTextColor(Color.BLACK);
ll.addView(label);
TextView value = new TextView(getActivity());
value.setPadding(20, 0, 20, 20);
value.setTextSize(17);
value.setTextColor(Color.BLACK);
value.setText(record.getString("value"));
ll.addView(value);
} else if (record.getString("valueType").equals("Image")) {
TextView label = new TextView(getActivity());
label.setText(record.getString("label"));
label.setPadding(20, 20, 20, 20);
label.setTextSize(20);
label.setTypeface(null, Typeface.BOLD);
label.setTextColor(Color.BLACK);
ll.addView(label);
byte[] decodedString = Base64.decode(record.getString("value"), Base64.DEFAULT);
Bitmap decodedByte = BitmapFactory.decodeByteArray(decodedString, 0, decodedString.length);
ImageView image = new ImageView(getActivity());
image.setImageBitmap(decodedByte);
image.setScaleType(ImageView.ScaleType.FIT_START);
}
}
}
progressDialog.dismiss();
progressDialog.cancel();
} else {
droidQuery.toast("Session Expired", Toast.LENGTH_LONG);
Intent intent = new Intent(getActivity(), LoginActivity.class);
startActivity(intent);
}
} catch (JSONException e) {
droidQuery.toast(e.toString(), Toast.LENGTH_SHORT);
}
}
}
).
error(new Function() {
#Override
public void invoke($ droidQuery, Object... params) {
Log.e("$", "broke good");
//DELETE THIS
Context context = getActivity();
CharSequence text = "Could not connect to Server";
int duration = Toast.LENGTH_LONG;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
}
));
}
}
For some reason when the app launches the fragment is blank as if nothing is added and I can't figure out why. I've tried added the linearlayout to the fragments xml and grabbing it by it's ID but I get a null reference error even though I do just that in another fragment elsewhere in the program and it works.
It looks like you're correctly adding the view to the Linear Layout you've created, but I don't see a spot where you're adding that newly created Layout to the Fragment's View.
Here is the documentation and an example
Taken from the example:
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
Modified to your specific situation:
populatePage(layout);
public void populatePage(View v){
...other code here...
RelativeLayout relativeLayout = (RelativeLayout)v. findViewById(R.id.id_that_exists_in_your_xml);
relativeLayout.addView(ll, 0, new ViewGroup.LayoutParams(RelativeLayout.LayoutParams.FILL_PARENT, RelativeLayout.LayoutParams.FILL_PARENT));
}
You're right, regarding your most recent edit, I made a mistake. Get reference to the base layout object in your XML file (Relative/Linear/Frame layout etc), and then call the addView method on that.
From the example you gave the ll object just created but never added to fragment. You can return LinearLayout object from populatePage() function and add it to fragment view in onCreateView.
I've searched all the posts I can find, and none seem to help with my situation. I have an android project that uses web services to pull down hourly weather data and populate a listView with the results.
The weird problem I'm having is that when I debug the project on my android phone, the main activity is blank and the listView isn't populated. If I run the project from android studio with my phone locked, and then unlock my phone the app opens on my phone with all of the listView properly formatted and populated.
I feel like it's a race condition issue between the asynctask and the adapter, but I can't seem to resolve it. I tried making my asyncTask an inner private class and calling notifyDataSetChanged on the adapter inside the onPostExecute method, but to no avail. I feel it must be something simple, but I'm relatively new to Android dev, so I'm stuck.
I have three classes that I'll post the pertinent code from
MainActivity.java (onCreate)
public class MainActivity extends ActionBarActivity {
ArrayList<Weather> w = new ArrayList<Weather>();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DownloadWeatherTask myTask = new DownloadWeatherTask(w);
WeatherAdapter myAdapter = new WeatherAdapter(this,w);
ListView l = (ListView) findViewById(R.id.weatherList);
l.setAdapter(myAdapter);
myTask.execute();
}
}
WeatherAdapter.java
public class WeatherAdapter extends ArrayAdapter<Weather>{
public WeatherAdapter(Context context, ArrayList<Weather> weather) {
super(context, R.layout.item_weather, weather);
}
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Weather forecast = getItem(position);
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_weather, parent, false);
}
// Lookup view for data population
TextView tvTime = (TextView) convertView.findViewById(R.id.listTime);
TextView tvDescr = (TextView) convertView.findViewById(R.id.listDescr);
TextView tvTemp = (TextView) convertView.findViewById(R.id.listTemp);
TextView tvHumid = (TextView) convertView.findViewById(R.id.listHumid);
ImageView ivWeather = (ImageView) convertView.findViewById(R.id.weatherImg);
// Populate the data into the template view using the data object
tvTime.setText(forecast.time);
tvDescr.setText(forecast.description);
tvTemp.setText(forecast.temperature+"°(F)");
tvHumid.setText(forecast.humidity+"% humidity");
ivWeather.setImageBitmap(forecast.weatherImg);
// Return the completed view to render on screen
return convertView;
}
}
DownloadWeatherTask.java
public class DownloadWeatherTask extends AsyncTask<Void,Void,Void>{
ArrayList<Weather> data;
public DownloadWeatherTask(ArrayList<Weather> a){
data = a;
}
public ArrayList<Weather> getData() {
return data;
}
protected Void doInBackground(Void...params) {
try {
String website = "http://api.wunderground.com/api/1111111111111/geolookup/q/autoip.json";
URL site = new URL(website);
HttpURLConnection weatherUnderground = (HttpURLConnection) site.openConnection();
weatherUnderground.connect();
JsonParser weatherParser = new com.google.gson.JsonParser();
JsonElement weatherJson = weatherParser.parse(new InputStreamReader((InputStream) weatherUnderground.getContent()));
JsonObject weatherObj = weatherJson.getAsJsonObject();
String zip = weatherObj.get("location").getAsJsonObject().get("zip").getAsString();
String city = weatherObj.get("location").getAsJsonObject().get("city").getAsString();
String state = weatherObj.get("location").getAsJsonObject().get("state").getAsString();
String hourly = "http://api.wunderground.com/api/111111111111/hourly/q/" + state + "/" + city + ".json";
URL hourlySite = new URL(hourly);
HttpURLConnection hourlyConnection = (HttpURLConnection) hourlySite.openConnection();
hourlyConnection.connect();
com.google.gson.JsonParser hourlyParser = new com.google.gson.JsonParser();
JsonElement hourlyWeatherJson = weatherParser.parse(new InputStreamReader((InputStream) hourlyConnection.getContent()));
JsonArray weatherArr = hourlyWeatherJson.getAsJsonObject().get("hourly_forecast").getAsJsonArray();
int l = weatherArr.size();
for (int i = 0; i < l; i++) {
String date = weatherArr.get(i).getAsJsonObject().get("FCTTIME").getAsJsonObject().get("pretty").getAsString();
String temp = weatherArr.get(i).getAsJsonObject().get("temp").getAsJsonObject().get("english").getAsString();
String condition = weatherArr.get(i).getAsJsonObject().get("condition").getAsString();
String humidity = weatherArr.get(i).getAsJsonObject().get("humidity").getAsString();
String iconUrl = weatherArr.get(i).getAsJsonObject().get("icon_url").getAsString();
Bitmap icon = getBitmapFromURL(iconUrl);
data.add(new Weather(date, condition, temp, humidity, icon));
}
} catch (IOException e) {
Log.e("Error: ",e.toString());
}
return null;
}
protected void onPostExecute(Void...params){
}
}
Below are links to my screenshots showing the app not populating the listView, and the app working properly when the program is run while the phone is initially locked.
Any help would be greatly appreciated!!
Thanks
In postExecute(), you need to update the adapter's List and then invoke its notifyDataSetChanged method. I suspect that you were forgetting to update the adapter's data.
The other option is to create a new adapter with the new data, and set the new adapter on the ListView.
I figured out what the issue was! I hadn't added #Override to my onPostExecute() method so it was never being called.
I added the notifyDataSetChanged to my onPostExecute as suggested, which worked once I added the #override to my method.
How can i do this?
something:
final View view=FLall.getChildAt(i);
if (view.getType()==ImageView) {
...
}
If, for some strange reason, you can't use Asahi's suggestion (using tags), my proposition would be the following:
if (view instanceof ImageView) {
ImageView imageView = (ImageView) view;
// do what you want with imageView
}
else if (view instanceof TextView) {
TextView textView = (TextView) view;
// do what you want with textView
}
else if ...
I try the following and it worked:
View view=FLall.getChildAt(i);
Log.i("ViewName", view.getClass().getName());
For Others who check this Question,in some cases instanceof does not work(I do not know why!),for example if your want to check if view type is ImageView or ImageButton(i tested this situation) , it get them the same, so you scan use this way :
//v is your View
if (v.getClass().getName().equalsIgnoreCase("android.widget.ImageView")) {
Log.e("imgview", v.toString());
imgview = (ImageView) v;
} else if (v.getClass().getName().equalsIgnoreCase("android.widget.ImageButton")) {
Log.e("imgbtn", v.toString());
imgbtn = (ImageButton) v;
}
You can use tag for that purpose:see set/getTag methods at http://developer.android.com/reference/android/view/View.html
I am using this solution for KOTLIN code, so going off of Arash's solution:
if(v.javaClass.name.equals("android.widget.ImageView", ignoreCase = true)) ...
using this didn't work for me, but tweaking it to:
if(v.javaClass.name.contains("ImageView", ignoreCase = true)) ...
worked for me!
In Kotlin you can check this by using "is":
val view = findViewById<View>(R.id.a_view)
if (view is ImageView) {
print("This is a ImageView")
} else {
print("This is not a ImageView")
}
In Android Xamarin, This is how Android get type of a view and compare with controller type.
var view = FindViewById<TextView>(Resource.Id.emailText);
if (typeof(TextView).IsInstanceOfType(view))
{
var textView = (TextView)view;
}