Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Existing patches for android tabwidget to allow tabs on left-hand side?

My employer is having me work on an android application with very specific UI requirements. Specifically, we need an interface that looks exactly like a TabWidget interface. However, having the tabs on the left hand side is an absolute must. We aren't going to be deploying this application to any android phones, its for an in house device, and as such don't have any problem violating any design considerations that the android platform might have.

We already have a working prototype that hacks together the functionality we need using a combination of focus listeners and list views. It isn't pretty, and we aren't very confident in it just yet, but it works for the time being.

What we'd really like is to throw all of our prototype UI code away in exchange for using the built in TabWidget. However, since TabWidget is hardcoded to only work with the tabs on top, this isn't really an option.

So, we are hoping that someone out there has a patch, or set of patches, or perhaps a custom class, that handles the TabWidget functionality with the tabs on the side instead?

The relevant code for the TabWidget is here: http://www.google.com/codesearch/p?hl=en#uX1GffpyOZk/core/java/android/widget/TabWidget.java&q=android%20package:git://android.git.kernel.org%20lang:java%20tabwidget&sa=N&cd=1&ct=rc

and the specific function that is hardcoded for being tabs on top is

private void initTabWidget() {
    setOrientation(LinearLayout.HORIZONTAL);
    mGroupFlags |= FLAG_USE_CHILD_DRAWING_ORDER;

    final Context context = mContext;
    final Resources resources = context.getResources();

    if (context.getApplicationInfo().targetSdkVersion <= Build.VERSION_CODES.DONUT) {
        // Donut apps get old color scheme
        if (mLeftStrip == null) {
            mLeftStrip = resources.getDrawable(
                    com.android.internal.R.drawable.tab_bottom_left_v4);
        }
        if (mRightStrip == null) {
            mRightStrip = resources.getDrawable(
                    com.android.internal.R.drawable.tab_bottom_right_v4);
        }
    } else {
        // Use modern color scheme for Eclair and beyond
        if (mLeftStrip == null) {
            mLeftStrip = resources.getDrawable(
                    com.android.internal.R.drawable.tab_bottom_left);
        }
        if (mRightStrip == null) {
            mRightStrip = resources.getDrawable(
                    com.android.internal.R.drawable.tab_bottom_right);
        }
    }

    // Deal with focus, as we don't want the focus to go by default
    // to a tab other than the current tab
    setFocusable(true);
    setOnFocusChangeListener(this);
}

If anyone has any information, I'd be much obliged.

like image 891
Michael Jones Avatar asked Nov 06 '22 09:11

Michael Jones


2 Answers

I've had this issue with tabs on the bottom. I ended up just copying all the tab background drawables and making buttons with stateful drawables and textcolor that looked like tabs which controlled a ViewFlipper in the main UI pane to switch between views.

like image 61
QRohlf Avatar answered Nov 13 '22 18:11

QRohlf


(Note that I added a better answer further down, past the line. I'm leaving this top one in in case it better fits someone else's needs.)

Yeah, I've been dealing with the same issue. I have a somewhat clunky solution. I noticed that you can rotate pretty much any View with setRotate. Unfortunately, this only rotates its image, or something, and doesn't fully deal with issues or placement or size or alignment. Even so, I've managed to cobble together something that kinda compensates for it, though it's only half done (doesn't quite work right if you rotate to portrait orientation). The following gets called whenever the tablet is rotated or the layout gets rearranged or whatever.

private LinearLayout llMain;
private LinearLayout ll1;
private LinearLayout mainView;
private TabHost myTabHost;

public void setStuff() {
    Display display = ((WindowManager) getSystemService(WINDOW_SERVICE)).getDefaultDisplay();
    if (display.getOrientation() == 0 || display.getOrientation() == 2) {
        ViewGroup.LayoutParams lp = myTabHost.getLayoutParams();
        int top = 0;
        int left = 0;
        int height = 696;
        int width = 1280;
        int centerx = (width / 2) + left;
        int centery = (height / 2) + top;
        lp.height = width;
        lp.width = height;
        myTabHost.setLayoutParams(lp);
        myTabHost.setTranslationX(centerx - (height / 2));
        myTabHost.setTranslationY(centery - (width / 2));
        lp = mainView.getLayoutParams();
        lp.width = 1280;
        lp.height = 696;
        mainView.setLayoutParams(lp);
        lp = llMain.getLayoutParams();
        lp.width = 1280;
        lp.height = 696;
        llMain.setLayoutParams(lp);

        ll1.setRotation(-90);
        lp = ll1.getLayoutParams();
        lp.height = 696;
        lp.width = 1141;
        ll1.setLayoutParams(lp);
        left = 0;
        top = 0;
        height = 696;
        width = 1141;
        centerx = (width / 2) + left;
        centery = (height / 2) + top;
        ll1.setTranslationX(centery - (width / 2));
        ll1.setTranslationY(centerx - (height / 2));
        //ll1.setTranslationX(tx);
        //ll1.setTranslationY(ty);
    } else {
        ViewGroup.LayoutParams lp = myTabHost.getLayoutParams();
        int top = 0;
        int left = 0;
        int height = 1280;
        int width = 696;
        int centerx = (width / 2) + left;
        int centery = (height / 2) + top;
        lp.height = width;
        lp.width = height;
        myTabHost.setLayoutParams(lp);
        myTabHost.setTranslationX(centerx - (height / 2));
        myTabHost.setTranslationY(centery - (width / 2));
        lp = mainView.getLayoutParams();
        lp.width = 696;
        lp.height = 1280;
        mainView.setLayoutParams(lp);
        lp = llMain.getLayoutParams();
        lp.width = 696;
        lp.height = 1280;
        llMain.setLayoutParams(lp);

        ll1.setRotation(-90);
        lp = ll1.getLayoutParams();
        lp.height = 1141;
        lp.width = 696;
        ll1.setLayoutParams(lp);
        left = 0;
        top = 0;
        height = 1141;
        width = 696;
        centerx = (width / 2) + left;
        centery = (height / 2) + top;
        ll1.setTranslationX(centery - (width / 1));
        ll1.setTranslationY(centerx - (height / 1));
        //ll1.setTranslationX(tx);
        //ll1.setTranslationY(ty);
    }
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    setStuff();
    //setContentView(R.layout.main);
} 

llMain contains mainView contains myTabHost contains ll1; you'll need to have assigned them as such in the initialization code. The idea is that the TabHost gets rotated clockwise, and its dimensions have to be manually swapped so that its containers know that it's a different size/shape, now, otherwise the edges get cut off. Also, it some calculations are done so that it get rotated around the right point, or at least ends up in the right place. The results didn't always make sense, so I just changed stuff until it worked, at least in landscape mode. The contents of the TabHost get rotated, too, so there's code in there that rotates it back, at least the first tab, which is ll1. Other tabs would need to be rotated back similarly. I messed around with this for a while, and there may be some things that are unnecessary. For example, the mainView. I think that doesn't need to be there. Oh, and if the TabHost is in a different place, the numbers will need to be adjusted somehow. Good luck with that. Anyway, I hope this helps somebody. Man, Android GUI is so aggravating...I wish they'd fix it.... I'll admit, though, that despite all the obstacles and frustrations, rotation of any component is pretty cool. I just wish everything else worked like you'd expect.


Hey, I just figured out how to get it to do it properly! The labels stay horizontal, so that may or may not be a good thing, depending on what you want, but anyway:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="vertical"
  android:layout_width="match_parent"
  android:layout_height="match_parent">
    <TabHost android:id="@android:id/tabhost" android:layout_width="match_parent" android:layout_height="match_parent">
        <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal">
            <FrameLayout android:layout_width="fill_parent" android:layout_height="match_parent" android:layout_weight="1" android:id="@android:id/tabcontent"></FrameLayout>
            <ScrollView android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:fillViewport="true"
                android:scrollbars="none">          
                <TabWidget android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" android:id="@android:id/tabs"></TabWidget>
            </ScrollView>
        </LinearLayout>
    </TabHost>

</LinearLayout>

This XML file defines an empty tabhost with the tabs on the right. Just add the tabs in your code; there're posts around for that. Copy/alter/do whatever you need to do to make it fit your needs. Also, because it's cool, I added a scroll view around the tabwidget, so it'll automatically allow scrolling if you have too many tabs. Get rid of it if you don't want it. Got the scroll thing mostly from http://java.dzone.com/articles/scrolling-tabs-android. Yay!

like image 38
Erhannis Avatar answered Nov 13 '22 20:11

Erhannis