fragments - how to use them with activities that r

2020-05-06 17:32发布

问题:

First - apologies for the newbie question.

I'm trying to implement a Navigation Drawer that will be used across my app. To start, I've followed the Android tutorial and created a basic navigation which changes a with Fragments.

I can pass a framelayout id and fragment to FragmentTransaction. It works great.

I decided to create a new login activity with the default android files (In Android Studio: going to new - activity - login activity ). This is what's confusing me. My questions are:

  1. Can I create a fragment of the login activity where the actions in LoginActivity will work? It looks like the fragment will create a view based on the layout passed, but the methods used in LoginActivity won't work?

  2. If creating a fragment does not work for the login activity, what would be the cleanest way to ensure the navigation works when switching activities? The Navigation Drawer only works when on the main activity; switching to other activities (via Intent) causes the app to lose the navigation drawer actions. The image of the actionbar/navigation drawer remains.

Here's some of my code in MainActivity ... maybe I'm missing something that is causing the navigation drawer to stop functioning when switching activities by Intent?

(Note: LoginActivity extends MainActivity in the LoginActivity class)

Thanks in advance for any direction / advice!

public class MainActivity extends ActionBarActivity {

private NavigationDrawerFragment mNavigationDrawerFragment;

//USER DATA
public String mUserID;
public String mToken;
public String mProgramData;

//NAVIGATION DRAWER
private CharSequence mTitle;
private CharSequence mDrawerTitle;
private String[] mTitles;

private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private ActionBarDrawerToggle mActionBarDrawerToggle;


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

    mTitle = mDrawerTitle = getTitle();

    // get list items for nav
    mTitles = getResources().getStringArray(R.array.nav_menu);

    //drawer widget
    mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);

    //listview of left drawer
    mDrawerList = (ListView) findViewById(R.id.left_drawer);

    // Set up the drawer.
    mDrawerList.setAdapter(new ArrayAdapter<>(this,
            R.layout.drawer_list_item, mTitles));

    //set onclicklistener on the each list item of menu options
    mDrawerList.setOnItemClickListener(new DrawerItemClickListener());

    // some styling...
    mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

    //enables action bar app behavior
    getSupportActionBar().setHomeButtonEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);

    // ties drawerlayout and actionbar for navigation drawers
    mActionBarDrawerToggle = new ActionBarDrawerToggle(
            this,
            mDrawerLayout,
            R.string.navigation_drawer_open,
            R.string.navigation_drawer_close) {

        // different titles for the drawer actions
        public void onDrawerClosed(View drawerView) {
            getSupportActionBar().setTitle(mTitle);
        }

        public void onDrawerOpened(View drawerView) {
            getSupportActionBar().setTitle(mDrawerTitle);
        }

    };

    // set drawer toggle as the drawer listener
    mDrawerLayout.setDrawerListener(mActionBarDrawerToggle);
}

 private class DrawerItemClickListener implements ListView.OnItemClickListener {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id){
        selectItem(position);
    }
}

@Override
protected void onPostCreate(Bundle savedInstanceState){
    super.onPostCreate(savedInstanceState);
    mActionBarDrawerToggle.syncState();
}

@Override
public void onConfigurationChanged(Configuration newConfig){
   super.onConfigurationChanged(newConfig);
   mActionBarDrawerToggle.onConfigurationChanged(newConfig);
}

    @Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();

    if (mActionBarDrawerToggle.onOptionsItemSelected(item)) {

        return true;
    }

    switch(id) {
        case R.id.action_home:
            Intent home = new Intent(this, MainActivity.class);
            this.startActivity(home);
            break;
        case R.id.action_login:
            Intent login = new Intent(this, LoginActivity.class);
            this.startActivity(login);
            break;
    }
    return super.onOptionsItemSelected(item);
}

EDIT

Thanks for your help so far in guiding me with my issue. Unfortunately I don't think I'm asking the right question, but maybe viewing the LoginActivity code from Android Studio would help.

This is part of LoginActivity:

public class LoginActivity extends MainActivity implements     LoaderCallbacks<Cursor> {

private UserLoginTask mAuthTask = null;

// UI references.
private AutoCompleteTextView mUserIDView;
private EditText mPasswordView;
private View mProgressView;
private View mLoginFormView;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_login);

        // Set up the login form.
        mUserIDView = (AutoCompleteTextView) findViewById(R.id.email);
        populateAutoComplete();

        mPasswordView = (EditText) findViewById(R.id.password);
        mPasswordView.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView textView, int id, KeyEvent keyEvent) {
                if (id == R.id.login || id == EditorInfo.IME_NULL) {
                    attemptLogin();
                    return true;
                }
                return false;
            }
        });

        Button mEmailSignInButton = (Button) findViewById(R.id.email_sign_in_button);
        mEmailSignInButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View view) {
                attemptLogin();
            }
        });

        mLoginFormView = findViewById(R.id.login_form);
        mProgressView = findViewById(R.id.login_progress);
    }



private void populateAutoComplete() {
    getLoaderManager().initLoader(0, null, this);
}


/**
 * Attempts to sign in or register the account specified by the login form.
 * If there are form errors (invalid email, missing fields, etc.), the
 * errors are presented and no actual login attempt is made.
 */
public void attemptLogin() {
    if (mAuthTask != null) {
        return;
    }

    // Reset errors.
    mUserIDView.setError(null);
    mPasswordView.setError(null);

    // Store values at the time of the login attempt.
    String email = mUserIDView.getText().toString();
    String password = mPasswordView.getText().toString();

    boolean cancel = false;
    View focusView = null;


    // Check for a valid password, if the user entered one.
    if (TextUtils.isEmpty(password)) {
        mPasswordView.setError(getString(R.string.error_invalid_password));
        focusView = mPasswordView;
        cancel = true;
    }

    // Check for a valid email address or ID.
    if (TextUtils.isEmpty(email)) {
        mUserIDView.setError(getString(R.string.error_field_required));
        focusView = mUserIDView;
        cancel = true;
    } else if (!isEmailValid(email) && !isIDValid(email)) {
        mUserIDView.setError(getString(R.string.error_invalid_email));
        focusView = mUserIDView;
        cancel = true;
    }

    if (cancel) {
        // There was an error; don't attempt login and focus the first
        // form field with an error.
        focusView.requestFocus();
    } else {
        // Show a progress spinner, and kick off a background task to
        // perform the user login attempt.
        showProgress(true);
        mAuthTask = new UserLoginTask(email, password);
        mAuthTask.execute((Void) null);
    }
}

private boolean isEmailValid(String email) {
    //TODO: Replace this with your own logic
    return email.contains("@");
}

private boolean isIDValid(String email) {
    //TODO: Replace this with your own logic
    return email.length() == 6;
}
[continued]...........

I'll create a simple fragment of LoginActivity called menu1_Fragment:

public class menu1_Fragment extends android.support.v4.app.Fragment {
View rootview;

public View onCreateView(LayoutInflater inflater, ViewGroup view, Bundle savedInstanceState) {

    rootview = (ViewGroup)inflater.inflate(R.layout.activity_login, null);
    return rootview;
}


}

If i'm correct (hopefully I'm wrong!) the fragment is replaced with the View (menu1_Fragment). The View cannot have actions (like clicking the login button to send a httppost request).

Also, could you explain why onOptionsItemSelected in MainActivity breaks the navigationdrawer (drawer becomes unclickable. also cannot swipe right to pull it up). Intent launches an activity (LoginActivity), but only the drawer in apperance shows.

回答1:

to hide also ActionBar icons you can do like:

 @Override
public boolean onOptionsItemSelected(MenuItem item) {
    // toggle nav drawer on selecting action bar app icon/title
    if (mDrawerToggle.onOptionsItemSelected(item)) {
        return true;
    }
    // Handle action bar actions click
    switch (item.getItemId()) {
        case R.id.action_settings:
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}

To replace main fragment when you click an item from the drawable menu list i see you have used selectItem(position) method, however that method is never declared on your code. To do that also you can do something like:

private void selectItem(int position){
    // update the main content by replacing fragments
    Fragment fragment = null;
    switch (position) {
        case 1:
            fragment = new TestFragment();
            break;
        case 2:
            fragment = new TestFragment2();
            break;
        default:
            break;
    }

    if (fragment != null) {
        FragmentManager fragmentManager = getSupportFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.content_frame, fragment).commit();

        // update selected item and title, then close the drawer
        setTitle(navMenuTitles[position]);
        mDrawerList.setItemChecked(position, true);
        mDrawerList.setSelection(position);
        mDrawerLayout.closeDrawer(mDrawerList);
    } else {
        // error in creating fragment
        Log.e("MainActivity", "Error in creating fragment");
    }
}


回答2:

I am giving you a example with multiple activities defined as fragment and called using MainActivity, Hope you will get your solution among it..

MainActivity.java

package com.example.fragmentdemo1;

import java.util.ArrayList;

import android.os.Bundle;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBarActivity;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity implements
        OnItemClickListener {

    MainActivity activity;
    private ListView lv;
    private ArrayList<String> list = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        activity = this;
        lv = (ListView) findViewById(R.id.listView);
        list.add("First");
        list.add("Second");
        list.add("Third");
        list.add("Forth");
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(activity,
                android.R.layout.simple_list_item_1, list);
        lv.setAdapter(adapter);

        lv.setOnItemClickListener(this);

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {

        switch (position) {
        case 0:
            Fragment1 f1 = new Fragment1();
            FragmentTransaction transaction = getSupportFragmentManager()
                    .beginTransaction();
            transaction.addToBackStack(null);
            transaction.replace(R.id.container, f1).commit();
            break;
        case 1:
            Fragment2 f2 = new Fragment2();
            FragmentTransaction transaction2 = getSupportFragmentManager()
                    .beginTransaction();
            transaction2.addToBackStack(null);
            transaction2.replace(R.id.container, f2).commit();

            break;
        case 2:
            Toast.makeText(activity, "" + position, 1000).show();
            Fragment3 f3 = new Fragment3();
            FragmentTransaction transaction3 = getSupportFragmentManager()
                    .beginTransaction();
            transaction3.addToBackStack(null);
            transaction3.replace(R.id.container, f3).commit();
            break;
        case 3:
            Fragment4 f4 = new Fragment4();
            FragmentTransaction transaction4 = getSupportFragmentManager()
                    .beginTransaction();
            transaction4.addToBackStack(null);
            transaction4.replace(R.id.container, f4).commit();
            break;
        default:
            break;
        }

    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        switch (id) {
        case android.R.id.home:

            finish();
            break;

        default:
            break;
        }

        return false;
    }

}

Fragment1.java

package com.example.fragmentdemo1;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;


public class Fragment1 extends android.support.v4.app.Fragment{

    TextView tv;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup view,
            Bundle savedInstanceState) {
        tv =(TextView)view.findViewById(R.id.textView1);
        view = (ViewGroup) inflater.inflate(R.layout.fragment1, null);
        return view;
    }
}

Fragment2.java

package com.example.fragmentdemo1;

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;

    public class Fragment2 extends Fragment {

        TextView tv;
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup view,
                Bundle savedInstanceState) {
            tv =(TextView)view.findViewById(R.id.textView2);
            view = (ViewGroup) inflater.inflate(R.layout.fragment2, null);
            return view;
        }
    }

Fragment3.java

package com.example.fragmentdemo1;

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;

    public class Fragment3 extends Fragment {
        TextView tv;
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup view,
                Bundle savedInstanceState) {

            tv =(TextView)view.findViewById(R.id.textView3);
            view =(ViewGroup)inflater.inflate(R.layout.fragment3, null);
            return view;
        }
    }

Fragment4.java

package com.example.fragmentdemo1;

import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

public class Fragment4 extends Fragment{

    TextView tv;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup view,
            Bundle savedInstanceState) {
        tv =(TextView)view.findViewById(R.id.textView4);

        view = (ViewGroup)inflater.inflate(R.layout.fragment4, null);
        return view;
    }
}

NOTE : If you want to use method from Fragment class to MainActivity, then you can make it public static, and you can use that method directly by it's class name like Fragment1.countData().

This demo also apply for Navigation drawer.