I have the following in my layout file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:visibility="gone"
android:id="#+id/topNav"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/stop_surfing"/>
<TextView
style="#style/Counter"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<WebView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
/>
</LinearLayout>
</LinearLayout>
When I run the method surf(), I was assuming that my linear layout would show, but instead nothing happens. Do I need to do something else to refresh the activity or something?
Here is the main activity:
public class MainActivity extends Activity{
public void onCreate(Bundle savedInstanceState){
// Snipped code //
WebView webView = (WebView)findViewById(R.id.webview);
webView.addJavascriptInterface(new JavaScriptBinder(this), "$js");
// Snipped code //
}
}
And here is the secondary class:
public class JavaScriptBinder{
Activity context;
JavaScriptBinder(Activity context){
this.context = context;
}
public void surf(String memberId){
// Snipped code //
LinearLayout top = (LinearLayout)context.findViewById(R.id.topNav);
top.setVisibility(View.VISIBLE);
}
}
surf() is called from a javascript file loaded in the webview:
function startSurfing(){
var users = document.getElementsByClassName("user");
for(var i = 0; i < users.length; i++){
users[i].addEventListener("click", function(e){
e.stopPropagation();
with(document.getElementById("black-overlay").style){
display = "block";
backgroundColor = "rgba(0,0,0,0.7)";
}
var userId = this.dataset.id;
$js.surf(userId);
}, false);
}
}
The documentation states that the code is run in a different Thread, so of course, you can't update your UI from this method just like this, see here:
http://developer.android.com/reference/android/webkit/WebView.html#addJavascriptInterface(java.lang.Object, java.lang.String)
JavaScript interacts with Java object on a private, background thread of this WebView. Care is therefore required to maintain thread safety.
So what you need to do, is to run that code in the UI Thread.
Also, you need to annotate your method with #JavascriptInterface, for the method to be callable for Android 4.2 and above.
Try with this:
#JavascriptInterface
public void surf(String memberId){
// Snipped code //
final LinearLayout top = (LinearLayout)context.findViewById(R.id.topNav);
context.runOnUiThread(new Runnable(){
#Override
public void run(){
top.setVisibility(View.VISIBLE);
}
});
}
Related
I am trying to switch between two WebViews in my layout with Android Java. The two WebViews load different urls when the oncreate method is called. The only problem am having is that the first webview shows up with the site content when oncreate is called but when I click the button that is supposed to show the next webview, it removes the current webview from view and then shows white screen. Help me resolve that, below is my layout file and the android java code behind file
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
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:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewSwitcher
android:layout_height="wrap_content"
android:id="#+id/viewSwitcher1"
android:layout_width="wrap_content">
<LinearLayout
android:id="#+id/view1"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.webkit.WebView
android:id="#+id/webView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:id="#+id/view2"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.webkit.WebView
android:id="#+id/webView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</ViewSwitcher>
<Button
android:id="#+id/button1"
android:text="Show Next"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</ScrollView>
and Android Java code for the behavior
public class MainActivity : AppCompatActivity
{
ViewSwitcher viewSwitcher;
private Button next;
protected WebView mywebview,webview2;
protected int mycount=0;
protected View view1, view2;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
viewSwitcher = FindViewById<ViewSwitcher>(Resource.Id.viewSwitcher1);
next = FindViewById<Button>(Resource.Id.button1);
mywebview = FindViewById<WebView>(Resource.Id.webView1);
webview2 = FindViewById<WebView>(Resource.Id.webView2);
view1 = FindViewById<View>(Resource.Id.view1);
view2 = FindViewById<View>(Resource.Id.view2);
WebViewClient client = mywebview.WebViewClient;
mywebview.LoadUrl("https://www.upwork.com");
webview2.LoadUrl("https:www.sololearn.com");
//set the in and out animation for the viewswitcher
viewSwitcher.SetOutAnimation(this, Resource.Animation.abc_slide_out_top);
viewSwitcher.SetInAnimation(this, Resource.Animation.design_bottom_sheet_slide_in);
next.Click += Next_Click;
//hide the action bar
}
private void Next_Click(object sender, System.EventArgs e)
{
if (viewSwitcher.CurrentView != view1)
{
viewSwitcher.ShowPrevious();
}else if(viewSwitcher.CurrentView != view2)
{
viewSwitcher.ShowNext();
}
}
}
as my title says I'm here with a problem in Android studio (JAVA) with my app, how to call class as an Activity when class has extends LinearLayout?
My class is:
public class CustomCalendar extends LinearLayout {
My code where I try to call it:
Intent customCalendar = new Intent(MainActivity.this, CustomCalendarActivity.class);
startActivity(customCalendar);
I tried to make this:
public class CustomCalendarActivity extends AppCompatActivity {
CustomCalendar customCalendar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customCalendar = (CustomCalendar) findViewById(R.id.kalendoriaus_virsus);
customCalendar.SetUpCalendar();
}
}
My crash is this:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.kalendorius.CustomCalendar.SetUpCalendar()' on a null object reference
at com.example.kalendorius.MainActivity$2.onClick(MainActivity.java:75)
75 Line is:
startActivity(customCalendar);
How I setup my calendar:
My kalendorius.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/kalendoriaus_virsus"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/soft_blue_green"
android:orientation="horizontal"
android:paddingTop="8dp"
android:paddingBottom="8dp">
<ImageButton
android:id="#+id/atgalBtn"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_margin="10dp"
android:background="#drawable/back" />
<TextView
android:id="#+id/dabartineData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:layout_weight="3"
android:gravity="center"
android:text="Data"
android:textColor="#ffffff"
android:textSize="18sp"
android:textStyle="bold" />
That's just a bit code where I use that kalendorius_virsus.
DONE. I figure out what was the problem. I just forgot to generate for database constructor:D Thank you for everyone who tried to help.
The problem is
customCalendar = (CustomCalendar) findViewById(R.id.kalendoriaus_virsus);
The groupView LinearLayout with id kalendorias_virsus in the kalendorias.xml is not a CustomCalendar so always return null.
You need to understand how to properly user a costum view
basic example CustomView ->
public class CustomView extends LinearLayout {
public CustomView(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
View view = LayoutInflater.from(getContext()).inflate(
R.layout.costum, null);
this.addView(view);
}
public void setCustomText(String text){
TextView textview = (TextView) findViewById(R.id.textViewId);
textview.setText(text);
}
}
layout custom.xml ->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/textViewId"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="#string/app_name"
android:gravity="center">
</TextView>
</LinearLayout>
activity.xml->
<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="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.example.myapplication.CustomView
android:id="#+id/customViewId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
MainActivity class->
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CustomView customView = findViewById(R.id.customViewId);
customView.setCustomText("Welcome ");
}
}
You have many errors in your code. We still need more information to determine why you are getting a NullPointerException (NPE) in the MainActivity.onClick() method. However, this will for sure crash:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
customCalendar = (CustomCalendar) findViewById(R.id.kalendoriaus_virsus);
customCalendar.SetUpCalendar();
}
because customCalendar will be null because you have not called setContentView() before calling findBiewById().
You need to add
setContentView(R.layout.XXXXXX);
before you call findViewById(). The XXXXXX above must be the name of your layout XML file (without the .xml file extension).
The basic view hierarchy is this:
secondActivity
linearLayout(LinearLayout)
constLayout(ConstraintLayout)
textbox(TextView)
image(ImageView)
image2
image3
...
The textbox TextView has visibility GONE, and goal is to make it VISIBLE on clicking other visible siblings, change some colors and text, and when clicked again it must be invisible again and reverse all changes.
Cant understand whatever it is that am missing. I have checked many older projects in which I did the same thing and cant find any visible differences as to why this code is not working now.
secondActivity.java
public class secondActivity extends Activity {
public boolean isTextBoxHidden;
public ConstraintLayout constLayout;
public TextView textbox;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
constLayout = findViewById(R.id.constLayout);
textbox = findViewById(R.id.textbox);
isTextBoxHidden = false;
// SETTING UP LISTENER
View.OnClickListener clickListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!isTextBoxHidden) {
constLayout.setBackgroundColor(Color.BLACK); //setting color on previously
v.setBackgroundColor(Color.BLACK); //setting color on visible view
textbox.setText("whatever");
textbox.setVisibility(View.VISIBLE); //was gone
isTextBoxHidden = true;
}
else {
textbox.setVisibility(View.GONE); //hide again
constLayout.setBackgroundColor(Color.WHITE);
v.setBackgroundColor(Color.WHITE);
isTextBoxHidden = false;
}
}
};
// INSERTING LISTENERS into all children
for(int i=0; i<constLayout.getChildCount(); i++) {
constLayout.getChildAt(i).setOnClickListener(clickListener);
}
}
}
activity_second.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:id="#+id/linearLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".secondActivity">
<android.support.constraint.ConstraintLayout
android:id="#+id/constLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#android:color/white">
<TextView
android:id="#+id/textbox"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:gravity="center"
android:text="example"
android:visibility="gone"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<ImageButton
android:id="#+id/image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:adjustViewBounds="true"
android:scaleType="fitXY"
android:src="#drawable/example"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"/>
<!--few more clones of the first imageButton-->
</android.support.constraint.ConstraintLayout>
</LinearLayout>
I can't see where you're setting textbox reference, so maybe that's a clue.
Edit:
Did compiled that example you have provided and everything works correctly, but i assume that [...] gone again for good meant you probably want this to be one shot action so instead of boolean just use Boolean and compare it to null.
Edit:
On the second thought you can just remove isTextBoxHidden = false; in else branch
I'm trying to create an activity where I have a GridLayout that is populated dynamically:
Here's the xml layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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:gravity="center"
android:orientation="vertical"
tools:context="GoalsActivity" >
<ScrollView
android:id="#+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<GridLayout
android:id="#+id/goals_grid"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:columnCount="2"
android:orientation="horizontal"
android:layout_gravity="center" >
</GridLayout>
</ScrollView>
</LinearLayout>
And here's the activity:
public class GoalsActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_goals);
try {
JSONArray goals = new JSONArray(getIntent().getStringExtra("GOAL_LIST"));
GridLayout goalsGrid = (GridLayout) findViewById(R.id.goals_grid);
for(int i = 0; i <= goals.length(); i++) {
JSONObject goal = goals.getJSONObject(i);
TextView goalView = new TextView(GoalsActivity.this);
goalView.setHeight(125);
goalView.setWidth(125);
goalView.setText(goal.getString("name"));
goalsGrid.addView(goalView);
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
As you can see I'm trying to display the goals using a GridLayout but whenever I run this code, the following happens:
Apparently all TextViews are stacking on top of each other, but if I add 2 of these:
<TextView
android:height="125dp"
android:width="125dp" />
under the GridLayout in my xml layout manually, they show up just like I need them to:
I can't figure out how to fix this, any help is greatly appreciated!
I'm having a hard time understanding how to update the view using data binding. I have a simple example I'm experimenting with, in which a toggle switch will make a button appear/disappear in the view.
Expected behavior:
The toggle button should toggle the "Add Key" button on/of (i.e. VISIBLE or GONE).
Actual behavior:
The "Add Key" button's visibility does not get updated. It only gets set once when the layout is loaded.
Here is the layout file:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="mainActivity"
type="tanager.sandbox.MainActivity" />
<variable
name="businessLogic"
type="tanager.sandbox.BusinessLogic" />
</data>
<RelativeLayout
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="tanager.sandbox.MainActivity">
<LinearLayout
android:id="#+id/linear_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<Button
android:id="#+id/add_key_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:visibility="#{businessLogic.getVisible()}"
android:text="#string/add_key" />
</LinearLayout>
<ToggleButton
android:id="#+id/toggleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="#id/linear_layout"
android:layout_weight="3"
android:text="ToggleButton"
android:onClick="#{() -> mainActivity.click()}"/>
</RelativeLayout>
</layout>
When the toggle button is pressed, it invokes a method on the main activity, which toggles a value in the business logic. I'm expecting the add_key_button to update its visibility automatically when the toggle button is pressed. Here is the MainActivity:
public class MainActivity extends AppCompatActivity {
private BusinessLogic _businessLogic;
#Override
protected void onCreate(Bundle savedInstanceState) {
_businessLogic = new BusinessLogic();
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ActivityMainBinding binding = DataBindingUtil.setContentView(this,
R.layout.activity_main);
binding.setMainActivity(this);
binding.setBusinessLogic(_businessLogic);
}
public void click() {
_businessLogic.toggleVisibility();
}
}
And here is the business logic class:
public class BusinessLogic extends BaseObservable {
private boolean visible;
public BusinessLogic(){
visible = true;
}
public void toggleVisibility(){
visible = !visible;
notifyPropertyChanged(BR.visible);
}
#Bindable
public int getVisible(){
return visible? View.VISIBLE:View.GONE;
}
}
I slightly refactored your code, this works
public void click() {
_businessLogic.toggleVisibility(binding.toggleButton.isChecked());
}
The BusinessLogic method now looks like
public class BusinessLogic extends BaseObservable {
private boolean isToggleOn;
public BusinessLogic() {
isToggleOn = false;
}
public void toggleVisibility(boolean toggleOn) {
isToggleOn = toggleOn;
notifyPropertyChanged(BR.toggleOn);
}
#Bindable
public boolean getToggleOn() {
return isToggleOn;
}
Then in the layout, you can set the visibility based on the getToggleOn method of the businessLogic class
<Button
android:id="#+id/add_key_button"
android:layout_width="match_parent"
android:visibility="#{businessLogic.toggleOn ? View.VISIBLE : View.GONE}"
android:layout_height="wrap_content"
android:text="Add key" />
Remember to import the view class in your layout
<data>
<import type="android.view.View"/>
<variable
name="mainActivity"
type="stackoverflow.MainActivity" />