Cancel Done buttons in Calendar App - Is it part o

2020-02-08 18:43发布

问题:

Hi, I'm refering the Cancel/Done button in Calendar app. These 2 buttons are pinned on the top, and they are always visible, even if you scrolling the bottom "form".

May I know, is it part of Action Bar? If so, how should the implementation look like?

回答1:

Remember that Android is open source, and most apps preinstalled on an android device running aosp are open source.

Here's the project: https://github.com/android/platform_packages_apps_calendar

Yes, it is a custom ActionBar setup, here's the XML:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dip
android:showDividers="middle">

<!-- id must match corresponding menu item id -->
<LinearLayout
    android:id="@+id/action_cancel
    style="@style/EditEventCustomActionButton">

<ImageView
    android:src="@drawable/ic_menu_cancel_holo_light"
    style="@style/EditEventCustomActionButtonImage" />
    <TextView
        android:text="@string/discard_label"
        style="@style/EditEventCustomActionButtonText" />

</LinearLayout>

<!-- id must match corresponding menu item id -->
<LinearLayout
    android:id="@+id/action_done"
    style="@style/EditEventCustomActionButton">

    <ImageView
        android:src="@drawable/ic_menu_done_holo_light"
        style="@style/EditEventCustomActionButtonImage" />
    <TextView
        android:text="@string/save_label"
        style="@style/EditEventCustomActionButtonText" />

    </LinearLayout
</LinearLayout>

That is later set on runtime:

View actionBarButtons = inflater.inflate(R.layout.edit_event_custom_actionbar,
new LinearLayout(mContext), false);
View cancelActionView = actionBarButtons.findViewById(R.id.action_cancel);
cancelActionView.setOnClickListener(mActionBarListener);
View doneActionView = actionBarButtons.findViewById(R.id.action_done);
doneActionView.setOnClickListener(mActionBarListener);
mContext.getActionBar().setCustomView(actionBarButtons);

Hope that helped



回答2:

Just for share... To implement into a sherlock fragment, the LayoutInflater used is the one from oncreateView method:

    setHasOptionsMenu(true);
    View actionBarButtons = inflater.inflate(R.layout.edit_event_custom_actionbar, new LinearLayout(getActivity()), false);

    View cancelActionView = actionBarButtons.findViewById(R.id.action_cancel);
    cancelActionView.setOnClickListener(mActionBarListener);

    View doneActionView = actionBarButtons.findViewById(R.id.action_done);
    doneActionView.setOnClickListener(mActionBarListener);


    getSherlockActivity().getSupportActionBar().setHomeButtonEnabled(false);
    getSherlockActivity().getSupportActionBar().setDisplayShowHomeEnabled(false);
    getSherlockActivity().getSupportActionBar().setDisplayHomeAsUpEnabled(false);
    getSherlockActivity().getSupportActionBar().setDisplayShowTitleEnabled(false);

    getSherlockActivity().getSupportActionBar().setDisplayShowCustomEnabled(true);
    getSherlockActivity().getSupportActionBar().setCustomView(actionBarButtons);

where the action bar listener is

private final View.OnClickListener mActionBarListener = new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        onActionBarItemSelected(v.getId());
    }
};

private boolean onActionBarItemSelected(int itemId) {
    switch (itemId) {
    case R.id.action_done:
        save();
        break;
    case R.id.action_cancel:
        System.err.println("cancel");
        getActivity().onBackPressed();
        break;
    }
    return true;
}

and the layout is the same of previous post:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:divider="?android:attr/dividerVertical"
android:dividerPadding="12dip
android:showDividers="middle">

<!-- id must match corresponding menu item id -->
<LinearLayout
    android:id="@+id/action_cancel
    style="@style/EditEventCustomActionButton">

<ImageView
    android:src="@drawable/ic_menu_cancel_holo_light"
    style="@style/EditEventCustomActionButtonImage" />
    <TextView
        android:text="@string/discard_label"
        style="@style/EditEventCustomActionButtonText" />

</LinearLayout>

<!-- id must match corresponding menu item id -->
<LinearLayout
    android:id="@+id/action_done"
    style="@style/EditEventCustomActionButton">

    <ImageView
        android:src="@drawable/ic_menu_done_holo_light"
        style="@style/EditEventCustomActionButtonImage" />
    <TextView
        android:text="@string/save_label"
        style="@style/EditEventCustomActionButtonText" />

    </LinearLayout
</LinearLayout>


回答3:

Based on daniel_c05's answer I was able to get this working in my app, however I needed a few additional steps which are not documented in either of the existing answers to get it working correctly.

1) You will need to retrieve the layout itself, quoted below for ease, originally from: https://github.com/android/platform_packages_apps_calendar/blob/master/res/layout/edit_event_custom_actionbar.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    android:divider="?android:attr/dividerVertical"
    android:dividerPadding="12dip
    android:showDividers="middle">

    <!-- id must match corresponding menu item id -->
    <LinearLayout
        android:id="@+id/action_cancel
        style="@style/EditEventCustomActionButton">

        <ImageView
            android:src="@drawable/ic_menu_cancel_holo_light"
            style="@style/EditEventCustomActionButtonImage" />

        <TextView
            android:text="@string/discard_label"
            style="@style/EditEventCustomActionButtonText" />

    </LinearLayout>

    <!-- id must match corresponding menu item id -->
    <LinearLayout
        android:id="@+id/action_done"
        style="@style/EditEventCustomActionButton">

        <ImageView
            android:src="@drawable/ic_menu_done_holo_light"
            style="@style/EditEventCustomActionButtonImage" />

        <TextView
            android:text="@string/save_label"
            style="@style/EditEventCustomActionButtonText" />

    </LinearLayout>
</LinearLayout>

2) You will also need the styles to go with it, quoted below for ease, originally from: https://github.com/android/platform_packages_apps_calendar/blob/master/res/values/styles.xml

<style name="EditEventCustomActionButton" parent="android:style/Widget.Holo.Light.ActionButton">
    <item name="android:layout_height">match_parent</item>
    <item name="android:layout_width">0dp</item>
    <item name="android:layout_weight">1</item>
    <item name="android:focusable">true</item>
    <item name="android:orientation">horizontal</item>
</style>

<style name="EditEventCustomActionButtonImage">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:padding">4dp</item>
</style>

<style name="EditEventCustomActionButtonText">
    <item name="android:layout_height">wrap_content</item>
    <item name="android:layout_width">wrap_content</item>
    <item name="android:textAppearance">?android:attr/actionMenuTextAppearance</item>
    <item name="android:textColor">?android:attr/actionMenuTextColor</item>
    <item name="android:orientation">horizontal</item>
    <item name="android:singleLine">true</item>
    <item name="android:ellipsize">none</item>
    <item name="android:padding">4dp</item>
</style>

3) You will also need to grab the button drawables, or replace them with your own, they are available in the various drawable folders here: https://github.com/android/platform_packages_apps_calendar/tree/master/res

4) The only thing missing now are the string resources which you can find at the link above, though I just replaced them with my own which I already had defined.

5) To actually make it work correctly, I had to do a little more than just inflating it. Below is the minimum amount I had to put in OnCreate to get it working. I was working with Xamarin, but I have put both a Java and Xamarin version for ease. Fair warning: I haven't tested the Java version.

Java

// Inflate the custom view and add click handlers for the buttons
View actionBarButtons = inflater.inflate(R.layout.edit_event_custom_actionbar,
    new LinearLayout(mContext), false);

View cancelActionView = actionBarButtons.findViewById(R.id.action_cancel);
cancelActionView.setOnClickListener(mActionBarListener);

View doneActionView = actionBarButtons.findViewById(R.id.action_done);
doneActionView.setOnClickListener(mActionBarListener);

// Retrieve an instance of the Activity's ActionBar
ActionBar actionBar = mContext.getActionBar();

// Hide the icon, title and home/up button
actionBar.setDisplayShowHomeEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(false);
actionBar.setDisplayShowTitleEnabled(false);

// Set the custom view and allow the bar to show it
actionBar.setCustomView(actionBarButtons);
actionBar.setDisplayShowCustomEnabled(true);

Xamarin C#

// Inflate layout for custom action bar with save & cancel buttons
var actionBarLayout = (LinearLayout)LayoutInflater.Inflate(
    Resource.Layout.ActionBarSave, new LinearLayout(BaseContext), false);

var saveButton = actionBarLayout.FindViewById<LinearLayout (Resource.Id.action_done);
saveButton.Click += saveButton_Click;

var cancelButton = actionBarLayout.FindViewById<LinearLayout>(Resource.Id.action_cancel);
cancelButton.Click += cancelButton_Click;

// Hide the icon, title and home/up button
ActionBar.SetDisplayShowHomeEnabled(false);
ActionBar.SetDisplayHomeAsUpEnabled(false);
ActionBar.SetDisplayShowTitleEnabled(false);

// Set the custom view and allow the bar to show it
var layoutParams = new ActionBar.LayoutParams(
    ActionBar.LayoutParams.MatchParent,
    ActionBar.LayoutParams.MatchParent);
ActionBar.SetCustomView(actionBarLayout, layoutParams);
ActionBar.SetDisplayShowCustomEnabled(true);

That is all that was required for me to get it working. I tried to be as comprehensive as possible, hopefully this will save someone from googling to try and find the steps missing from the other answers.