I have done a code sample of what I need but I get invisible Grid Lines. Not sure why it's not working, I've tried different settings but no luck, here is the code. Sorry for the mess in the code:
FXMLdocument.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.canvas.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.paint.*?>
<?import javafx.scene.effect.*?>
<?import javafx.embed.swing.*?>
<?import javafx.scene.chart.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.shape.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" fx:id="anchorPane" prefHeight="1006.0" prefWidth="1219.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="GUI.FXMLDocumentController">
<children>
<MenuBar layoutX="-1.0" layoutY="2.0" prefHeight="25.0" prefWidth="826.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="2.0">
<menus>
<Menu mnemonicParsing="false" onAction="#menuOverview" text="Overview">
<items>
<CheckMenuItem fx:id="RR_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="1" />
<CheckMenuItem fx:id="RRAnt_Status" mnemonicParsing="false" text="2" />
<CheckMenuItem fx:id="IFF_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="3" />
<CheckMenuItem fx:id="ESM_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="4" />
<CheckMenuItem fx:id="Link_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="5" />
<CheckMenuItem fx:id="C2_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="6" />
<CheckMenuItem fx:id="Ais_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="7" />
<CheckMenuItem fx:id="Msr_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="8" />
<CheckMenuItem fx:id="EOS_Status" mnemonicParsing="false" onAction="#enableCheckBox" text="9" />
</items>
</Menu>
</menus>
<effect>
<InnerShadow />
</effect>
</MenuBar>
<Group />
<SwingNode layoutX="28.0" layoutY="171.0" />
<Pane fx:id="GridPane" layoutX="34.0" layoutY="51.0" prefHeight="553.0" prefWidth="1160.0">
<children>
<ScrollPane layoutX="43.0" layoutY="337.0" prefHeight="200.0" prefWidth="1049.0" vbarPolicy="NEVER">
<content>
<GridPane fx:id="grid" gridLinesVisible="true">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
</GridPane>
</content>
</ScrollPane>
</children>
</Pane>
</children>
</AnchorPane>
FXMLDocumentController.java
package GUI;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.AnchorPane;
import javafx.stage.Stage;
public class FXMLDocumentController implements Initializable {
#FXML
private MenuItem mnuClose;
#FXML
private AnchorPane anchorPane;
#FXML
private CheckMenuItem RR_Status;
#FXML
private CheckMenuItem IFF_Status;
#FXML
private CheckMenuItem ESM_Status;
#FXML
private CheckMenuItem Link_Status;
#FXML
private CheckMenuItem C2_Status;
#FXML
private CheckMenuItem Ais_Status;
#FXML
private CheckMenuItem EOS_Status;
#FXML
private CheckMenuItem Msr_Status;
//clickable grid
#FXML
private GridPane grid;
//Variable used by table
Integer i = 0;
Integer i_overMsg = 0;
Integer rr_status_row_index;
Integer iff_bit_row_index;
Integer iff_status_row_index;
Integer c2_status_row_index;
Integer esm_status_row_index;
Integer ais_status_row_index;
Integer link_status_row_index;
static Integer doSwitch(Boolean in){
Integer out;
if (in==true)
out = 1;
else
out = 0;
return out;
}
#Override
public void initialize(URL url, ResourceBundle rb) {
if (doSwitch(RR_Status.isSelected())==1) {
String colorname = "Red";
//Status of messages into an array
String[] ArrayColor = new String[11];
ArrayColor[0] = "Red";
ArrayColor[1] = "Green";
ArrayColor[2] = "Yellow";
ArrayColor[3] = "Yellow";
ArrayColor[4] = "Yellow";
ArrayColor[5] = "Yellow";
rr_status_row_index=i;
i++;
i_overMsg++;
}
if (doSwitch(IFF_Status.isSelected())==1) {
//For the clickable grid
grid.addRow(i, new Label("3"));
System.out.println(i);
iff_status_row_index=i;
i++;
grid.addRow(i, new Label("3"));
iff_bit_row_index=i;
i++;
}
//grid.getRowConstraints().add(new RowConstraints(30));
grid.addRow(i, new Label("I am fixed!"));
}
//Method to draw the Grid Panels when action in Menu Overview
#FXML
private void menuOverview(ActionEvent event) {
Integer i = 0;
// CLear previously created Grid Panel
grid.getChildren().clear();
grid.setGridLinesVisible(true);
grid.setStyle("-fx-grid-lines-visible: true;");
if (RR_Status.isSelected()) {
//draw row in Grid Panel
String colorname = "Red";
//Status of messages into an array
String[] ArrayColor = new String[11];
ArrayColor[0] = "Red";
ArrayColor[1] = "Green";
ArrayColor[2] = "Yellow";
ArrayColor[3] = "Yellow";
ArrayColor[4] = "Yellow";
ArrayColor[5] = "Yellow";
//Add label for the RR Status Row
grid.addRow(i, new Label("1"));
for(int count=0; count<11; count++){
Label txt = new Label(" ");
grid.add(txt,count,i);
grid.setGridLinesVisible(true);
grid.setStyle("-fx-grid-lines-visible: true;");
if (count ==3) {
txt.setStyle("-fx-background-color: black;");
}
if (count ==5) {
txt.setStyle("-fx-background-color: blue;");
}
}
rr_status_row_index=i;
i++;
//END draw row for RR_Status
grid.setGridLinesVisible(true);
grid.setStyle("-fx-grid-lines-visible: true;");
}
if (IFF_Status.isSelected()) {
//draw row in Grid Panel
grid.addRow(i, new Label("3"));
System.out.println(i);
iff_status_row_index=i;
i++;
grid.addRow(i, new Label("3"));
iff_bit_row_index=i;
i++;
//END draw row in Grid Panel
}
if (ESM_Status.isSelected()) {
//draw row in Grid Panel
grid.addRow(i, new Label("4"));
System.out.println(i);
esm_status_row_index=i;
i++;
//END draw row in Grid Panel
}
if (C2_Status.isSelected()) {
//draw row in Grid Panel
grid.addRow(i, new Label("6"));
System.out.println(i);
c2_status_row_index=i;
i++;
//END draw row in Grid Panel
}
if (Ais_Status.isSelected()) {
//draw row in Grid Panel
grid.addRow(i, new Label("7"));
System.out.println(i);
ais_status_row_index=i;
i++;
//END draw row in Grid Panel
}
if (Link_Status.isSelected()) {
//draw row in Grid Panel
grid.addRow(i, new Label("5"));
System.out.println(i);
link_status_row_index=i;
i++;
//END draw row in Grid Panel
}
//Draw the fixed row in Grid Panel
grid.addRow(i, new Label("I am fixed!"));
grid.setGridLinesVisible(true);
grid.setStyle("-fx-grid-lines-visible: true;");
}
// NOT USED IN THIS EXAMPLE
//Method to handle the checkboxes connected to the Menu Items
#FXML
private void enableCheckBox(ActionEvent event) {
//Check if RR Menu item is enabled
if (RR_Status.isSelected()) {
}
else {
}
//Check if IFF Menu item is enabled or disabled
if (IFF_Status.isSelected()) {
}
else {
}
//Check if ESM Menu item is enabled or disabled
if (ESM_Status.isSelected()) {
}
else {
}
//Check if C2 Menu item is enabled or disabled
if (C2_Status.isSelected()) {
}
else {
}
//Check if AIS Menu item is enabled or disabled
if (Ais_Status.isSelected()) {
}
else {
}
//Check if LINK Menu item is enabled or disabled
if (Link_Status.isSelected()) {
}
else {
}
//Check if MSR Menu item is enabled or disabled
if (Msr_Status.isSelected()) {
}
else {
}
//Check if EOS Menu item is enabled or disabled
if (EOS_Status.isSelected()) {
}
else {
}
}
// END NOT USED IN THIS EXAMPLE
}
JavaFXApplication1.java
package GUI;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class JavaFXApplication1 extends Application {
#Override
public void start(Stage stage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("FXMLdocument.fxml"));
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Tester");
stage.show();
}
public static void main(String[] args) {
launch(args);
}
}
So before selecting a menu item in the overview Menu, gridlines are shown, but after selecting/deselecting a menuitem, a new Grid layout is created but with no visible gridlines. How can I get the gridlines to be shown?
Thanks!
Related
I can successfully add a MenuFlyoutItem to a MenuFlyout dynamically in the ContextMenuFlyout_Opening event, but when I try to remove it in ContextMenuFlyout_Closing the MenuFlyout.Items is always null and the MFI isnt found and removed.
Any ideas why this is so?
<Page.Resources>
<MenuFlyout
x:Key="ListViewContextMenu"
Closing="{x:Bind ViewModel.ContextMenuFlyout_Closing}"
Opening="{x:Bind ViewModel.ContextMenuFlyout_Opening}">
<MenuFlyoutItem
Click="{x:Bind ViewModel.EditParty}"
Icon="Edit"
Text="Edit" />
<MenuFlyoutItem Text="Open in new window">
<MenuFlyoutItem.Icon>
<FontIcon
FontFamily="Segoe MDL2 Assets"
FontSize="40"
Glyph="" />
</MenuFlyoutItem.Icon>
</MenuFlyoutItem>
<MenuFlyoutSeparator />
<MenuFlyoutItem
Click="MenuFlyoutItem_Click"
Icon="Delete"
Text="Delete" />
</MenuFlyout>
</Page.Resources>
ViewModel event handlers
public void ContextMenuFlyout_Opening(object sender, object e)
{
MenuFlyout flyout = sender as MenuFlyout;
if (flyout != null)
{
// If party.IsConflict = true then add the MFI
if (SelectedTalent.IsConflict)
{
flyout.Items.Add(new MenuFlyoutItem()
{
Icon = new FontIcon() { Glyph = "\uEC4F" },
Text = "Resolve Conflict"
});
}
}
}
public void ContextMenuFlyout_Closing(object sender, object e)
{
// Remove 'Resolve Conflict' MFI if its found
MenuFlyout flyout = sender as MenuFlyout;
if (flyout != null)
{
var rc = flyout.Items.FirstOrDefault(o => o.Name == "Resolve Conflict");
if (rc != null)
{
flyout.Items.Remove(rc);
}
}
}
ListView that uses the MenuFlyout
<ListView
ContextFlyout="{StaticResource ListViewContextMenu}"
Based on your code, it seems that you are trying to get the MenuFlyoutItem object by name. But you forget to give the MenuFlyoutItem object a Name when you add it to the MenuFlyout, you just added a Text property.
flyout.Items.Add(new MenuFlyoutItem()
{
Icon = new FontIcon() { Glyph = "\uEC4F" },
Text = "Resolve Conflict",
Name = "Resolve Conflict",
});
In my Xamarin.Forms app, I have MaterialFrame custom control.
iOS renderer works great and looks like:
public class MaterialFrameRenderer : FrameRenderer
{
private const int ShadowColor = 0x939393;
public override void Draw(
CGRect rect)
{
base.Draw(rect);
// Update shadow to match better material design standards of elevation
Layer.ShadowRadius = Layer.CornerRadius;
Layer.ShadowColor = ColorHelper.FromHex(ShadowColor).CGColor;
Layer.ShadowOffset = new CGSize(1, 1);
Layer.ShadowOpacity = 0.30f;
Layer.ShadowPath = UIBezierPath.FromRect(Layer.Bounds).CGPath;
Layer.MasksToBounds = false;
}
}
On Android platform I want to use implementation based on my other cross-platform control. My .net standard(shared project) implementation:
public class MaterialFrame : Frame
{
public MaterialFrame()
{
if (Device.RuntimePlatform == Device.Android)
{
Content = new MyOtherCustomControl
{
BackgroundColor = Color.Red
};
}
}
}
Unfortunately this implementation doesn't work on Android. Do you have any suggestion?
I create the MyOtherCustomControl.
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="MyOtherCustomControl"
VerticalOptions="CenterAndExpand" />
<Button />
</StackLayout>
And use it in MaterialFrame custom control.
public class MaterialFrame : Frame
{
public MaterialFrame()
{
if (Device.RuntimePlatform == Device.Android)
{
Content = new MyOtherCustomControl
{
BackgroundColor = Color.Red
};
}
}
}
Usage of MaterialFrame:
<ContentPage.Content>
<StackLayout>
<Label
HorizontalOptions="CenterAndExpand"
Text="Welcome to Xamarin.Forms!"
VerticalOptions="CenterAndExpand" />
<pages:MaterialFrame />
</StackLayout>
</ContentPage.Content>
Screenshot:
I have two pages MainPage and SecondPage1 .in App.xaml.cs I Navigate to Secondpage1 using this code:
App.xaml.cs :
//MainPage = new Fmkt44Application.MainPage();/*First Approach*/
MainPage = new NavigationPage(new MainPage());/*Second approach*/
MainPage.xaml.cs:
// App.Current.MainPage = new NavigationPage(new SecondPage1());/*First Approach*/
await Navigation.PushAsync(new SecondPage1());/*Second approach*/
Problem is if I use both approaches I can navigate to secondpage1 but if I use second approach I cant write on searchbar or any entries. What is the reason and how can I Fix it?
Here is MainPage.xaml.cs
namespace Fmkt44Application
{
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
public async System.Threading.Tasks.Task LoginControlAsync(Object sender, EventArgs args)
{
User.UserName = entry_user.Text;
User.Password = entry_passw.Text;
if (User.CheckUserInformation() == false)
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresini giriniz", "OK");
}
else
{
String val = entry_user.Text + "$" + entry_passw.Text;
CallIasWebService.Login();
String rval = CallIasWebService.CallIASService("PROFILECONTROL", val);
CallIasWebService.Logout();
User.Profile = rval.ToString();
if (rval != "0" )
{
if (User.Profile != "" && User.Profile != null)
{
// App.Current.MainPage = new NavigationPage(new SecondPage1());if I Call Like this I can write on Secondpage1 (First approach)
await Navigation.PushAsync(new SecondPage1());/*I cannot reach SecondPage1 controls/* (second approach)*/
}
else
{
DisplayAlert("Login", "Kayıt yapma yetkiniz yoktur.", "OK");
}
}
else
{
DisplayAlert("Login", "Kullanıcı Adını veya şifresi hatalıdır.", "OK");
}
}
}
public async System.Threading.Tasks.Task scanncontrolAsync(Object sender, EventArgs E)
{
// await Navigation.PushAsync(new SecondPage1());
App.Current.MainPage = new SecondPage1();
}
}
}
App.cs is
public App ()
{
InitializeComponent();
//MainPage = new Fmkt44Application.MainPage();(First apploach)
MainPage = new NavigationPage(new MainPage());/*second approach*/
}
Secondpage1.xaml is
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Fmkt44Application.SecondPage1">
<ContentPage.Content>
<StackLayout>
<SearchBar Placeholder="Ara..." TextChanged="TextChange" x:Name="searchbar" />
<ListView x:Name="Materials" ItemTapped="MakineSec" HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<StackLayout Orientation="Horizontal" >
<Label Text="{Binding Material}"/>
<Label Text="{Binding Stext}"/>
</StackLayout>
<Entry Text="{Binding SerialNumber}" />
</StackLayout>
<ViewCell.ContextActions>
<MenuItem Text="Seç" Clicked="MakineSec" CommandParameter="{Binding .}"/>
</ViewCell.ContextActions>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
Problem comes from Android Emulator. I tried a real tablet problem solved.
first of all sorry for my english.
I am working on a iOS and Android project using Xamarin.Form
I would like to have a 'xaml user control' reusable in different way, and I need to make it clickable with ICommand
This is the StackLayoutButton component:
<?xml version="1.0" encoding="utf-8" ?>
<StackLayout xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Installa.Controls.StackLayoutButton">
<Image x:Name="Icon" Source="{Binding Icon}" />
<Label x:Name="Text" Text="{Binding Title}" HorizontalOptions="Center" LineBreakMode="NoWrap" Font="Small" TextColor="Red" />
</StackLayout>
This is the CalendarioPage xaml page where the component is used
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:controls="clr-namespace:Installa.Controls;assembly=Installa"
x:Class="Installa.CalendarioPage">
<StackLayout>
<Label Text="{Binding ViewName}" Font="42" IsVisible="{Binding IsWindowsPhone}" />
<ActivityIndicator IsRunning="{Binding IsLoading}" IsVisible="{Binding IsLoading}" Color="Red" />
<controls:StackLayoutButton BindingContext="{Binding Blog}" TextColor="Blue" /> <!-- Command="{Binding SubmitCommand}" -->
<controls:StackLayoutButton BindingContext="{Binding Facebook}" TextColor="Red" /> <!-- Command="{Binding SubmitCommand}" -->
</StackLayout>
</ContentPage>
This is the CalendarioPage c# page:
public partial class CalendarioPage : ContentPage
{
private CalendarioViewModel vm;
public CalendarioPage()
{
InitializeComponent();
vm = new CalendarioViewModel();
this.BindingContext = vm;
}
}
This is the viewmodel class:
namespace Installa
{
public class CalendarioViewModel: BaseViewModel
{
public CalendarioViewModel()
{
blog = new Activity();
blog.Link = "www.google.it";
blog.Title = "Titolo del blog";
blog.Icon = "logomenu.png";
facebook = new Activity();
facebook.Title = "Tito Fbook";
facebook.Link = "www.facebook.it";
facebook.Icon = "icon.png";
ViewName = "nome della view";
IsLoading = false;
}
Activity blog = null;
public Activity Blog
{
get {return blog;}
}
Activity facebook = null;
public Activity Facebook
{
get { return facebook; }
}
string viewName = string.Empty;
public string ViewName
{
get { return viewName; }
set { SetProperty(ref viewName, value); }
}
public bool IsWindowsPhone
{
get
{
return Device.OS == TargetPlatform.WinPhone;
}
}
bool isLoading = false;
public bool IsLoading
{
get { return isLoading; }
set { SetProperty(ref isLoading, value); }
}
}
}
With Activity a simple class with:
public string Title { get; set; }
public string Link { get; set; }
public String Icon { get; set; }
Till now, all is working right, but now I need to implement the ICommand interface.
In StackLayoutButton c# code I try to add:
var tapGestureRecognizer = new TapGestureRecognizer();
tapGestureRecognizer.SetBinding(TapGestureRecognizer.CommandProperty, "TapCommand");
Icon.GestureRecognizers.Add(tapGestureRecognizer)
Text.GestureRecognizers.Add(tapGestureRecognizer)
Furthermore I try to add into CalendarioViewModel INotifyPropertyChanged and the 'OnTapped' method.
Into Activity.cs i add 'ICommand tapCommand' and the related get...but is not working.
I try even other..but I am not able to enable the tap on the StackLayoutButton components.
In wich way I should do ?
I'd like to be able to have a 'programmable' command...for example I would like browse to 'the link property' of Activity or be able to open a new view.
Thanks for help!
Update:
I was able to add TapGestureRecognizer into the xaml user control (StackLayoutButton.xaml.cs),
but I'd like to implement it in MVVM way,
using Xamarin.Forms;
namespace Installa.Controls
{
public partial class StackLayoutButton : StackLayout
{
public StackLayoutButton()
{
InitializeComponent();
TapGestureRecognizer tapGestureRecognizer = new TapGestureRecognizer
{
Command = new Command(OnMyComponentTapped),
CommandParameter = "ciao"
};
this.Icon.GestureRecognizers.Add(tapGestureRecognizer);
this.Text.GestureRecognizers.Add(tapGestureRecognizer);
}
async void OnMyComponentTapped(object parameter)
{
// do action
}
public Color TextColor
{
get { return this.Text.TextColor; }
set { this.Text.TextColor = value; }
}
public Label TextControl
{
get { return this.Text; }
set { this.Text = value; }
}
}
}
can anyone suggest me the way ?
Thanks
This is how I add gesture recognizer on my xaml view:
<Label.GestureRecognizers>
<TapGestureRecognizer Command="{Binding SelectEquipmentCommand}"/>
</Label.GestureRecognizers>
And this is the ICommand property in my ViewModel:
public ICommand SelectEquipmentCommand
{
get
{
return fSelectEquipmentCommand ?? (fSelectEquipmentCommand = new Command(async () => await SelectEquipmentTask()));
}
}
private async Task SelectEquipmentTask()
{
}
I am following the tutorial of the official android SDK,and try to write a simple log in program.
So what I did is..
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.logintutorial"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/app_id"/>
</manifest>
The MainActivity simply uses fragment transaction.
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
public class MainActivity extends FragmentActivity {
private MainFragment mainFragment;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
// Add the fragment on initial activity setup
mainFragment = new MainFragment();
getSupportFragmentManager()
.beginTransaction()
.add(android.R.id.content, mainFragment)
.commit();
} else {
// Or set the fragment from restored state info
mainFragment = (MainFragment) getSupportFragmentManager()
.findFragmentById(android.R.id.content);
}
}
}
The MainFragment class is used for the Session Management with the help of the UiLifecyleHelper and the Session.StatusCallBack class.
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.facebook.Session;
import com.facebook.SessionState;
import com.facebook.UiLifecycleHelper;
import com.facebook.widget.LoginButton;
public class MainFragment extends Fragment {
private static final String TAG = "MainFragment";
private UiLifecycleHelper uiHelper;
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(final Session session, final SessionState state, final Exception exception)
{
onSessionStateChange(session, state, exception);
}
};
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_main, container, false);
LoginButton authButton = (LoginButton) view.findViewById(R.id.authButton);
authButton.setFragment(this);
//authButton.setReadPermissions(Arrays.asList("user_likes", "user_status"));
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
uiHelper = new UiLifecycleHelper(getActivity(), callback);
uiHelper.onCreate(savedInstanceState);
}
#Override
public void onResume() {
super.onResume();
// For scenarios where the main activity is launched and user
// session is not null, the session state change notification
// may not be triggered. Trigger it if it's open/closed.
Session session = Session.getActiveSession();
if (session != null &&
(session.isOpened() || session.isClosed()) ) {
onSessionStateChange(session, session.getState(), null);
}
uiHelper.onResume();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
}
#Override
public void onPause() {
super.onPause();
uiHelper.onPause();
}
#Override
public void onDestroy() {
super.onDestroy();
uiHelper.onDestroy();
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
uiHelper.onSaveInstanceState(outState);
}
private void onSessionStateChange(Session session, SessionState state, Exception exception) {
if (state.isOpened()) {
Log.i(TAG, "Logged in...");
} else if (state.isClosed()) {
Log.i(TAG, "Logged out...");
}
}
}
Also the main activity's xml file...
<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:orientation="vertical">
<com.facebook.widget.LoginButton
android:id="#+id/authButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:layout_marginTop="30dp"
/>
</LinearLayout>
and finally I put the app id in the string.xml file as
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Login Tutorial</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
<string name="app_id">XXX6999249XXXXX</string>
</resources>
When I run it, I get the following exception.
11-10 13:01:46.784: E/AndroidRuntime(31157): FATAL EXCEPTION: main
11-10 13:01:46.784: E/AndroidRuntime(31157): java.lang.RuntimeException:
Unable to start activity
ComponentInfo{com.example.logintutorial/com.example.logintutorial.MainActivity}:
java.lang.NullPointerException: Argument 'applicationId' cannot be null
The metadata tag has to be inside the application tag and not outside!. Change manifest to:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.logintutorial"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="20" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<meta-data
android:name="com.facebook.sdk.ApplicationId"
android:value="#string/app_id"/>
</application>
</manifest>