Android Listview重心屏幕中心

时间:2014-11-13 04:07:29

标签: android android-layout layout

我想知道如何在LinearLayout的中心调整listview activity_main_menu_listview 。我尝试了重力,但它不适合我,但当我给它保证金,所以它的工作。但我想要它自动,所以我该怎么办呢? 感谢

<com.entropy.slidingmenu2.layout.MainLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >

 <!-- This holds our menu -->
 <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"   
    android:orientation="vertical" >

    <ListView
        android:id="@+id/activity_main_menu_listview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:divider="@android:color/transparent"
        android:cacheColorHint="#00000000" >
    </ListView>
</LinearLayout>

<!-- This holds our content-->
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <!-- This acts as Actionbar -->
   <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:layout_marginTop="5dp"
        android:layout_marginLeft="5dp"
        android:orientation="horizontal" >

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:onClick="toggleMenu"
            android:background="@drawable/menu_btn"
            android:id="@+id/activity_main_content_button_menu" />



    </LinearLayout>       

    <!-- This is where fragment will show up -->
    <FrameLayout
        android:id="@+id/activity_main_content_fragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" >

    </FrameLayout>

</LinearLayout>

MainLayout代码:

public class MainLayout extends LinearLayout {

// Duration of sliding animation, in miliseconds
private static final int SLIDING_DURATION = 500;

// Query Scroller every 16 miliseconds
private static final int QUERY_INTERVAL = 16;

// MainLayout width
int mainLayoutWidth;

// Sliding menu
private View menu;

// Main content
private View content;

// menu does not occupy some right space
// This should be updated correctly later in onMeasure
private static int menuRightMargin = 120;

// The state of menu
private enum MenuState {
    HIDING,
    HIDDEN,
    SHOWING,
    SHOWN,
};

// content will be layouted based on this X offset
// Normally, contentXOffset = menu.getLayoutParams().width = this.getWidth - menuRightMargin
private int contentXOffset;

// menu is hidden initially
private MenuState currentMenuState = MenuState.HIDDEN;

// Scroller is used to facilitate animation
private Scroller menuScroller = new Scroller(this.getContext(),
        new EaseInInterpolator());

// Used to query Scroller about scrolling position
// Note: The 3rd paramter to startScroll is the distance
private Runnable menuRunnable = new MenuRunnable();
private Handler menuHandler = new Handler();

// Previous touch position
int prevX = 0;

// Is user dragging the content
boolean isDragging = false;

// Used to facilitate ACTION_UP 
int lastDiffX = 0;

// Constructor

// 3 parameters constructor seems to be unavailable in 2.3
/*
public MainLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
}
*/

public MainLayout(Context context, AttributeSet attrs) {
    super(context, attrs);
}

public MainLayout(Context context) {
    super(context);
}

// Overriding LinearLayout core methods

// Ask all children to measure themselves and compute the measurement of this
// layout based on the children
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    mainLayoutWidth = MeasureSpec.getSize(widthMeasureSpec);
    menuRightMargin = mainLayoutWidth * 30 / 100;
    // Nothing to do, since we only care about how to layout
}

// This is called when MainLayout is attached to window
// At this point it has a Surface and will start drawing. 
// Note that this function is guaranteed to be called before onDraw
@Override
protected void onAttachedToWindow() {
    super.onAttachedToWindow();

    // Get our 2 child View
    menu = this.getChildAt(0);
    content = this.getChildAt(1);   

    // Attach View.OnTouchListener
    content.setOnTouchListener(new OnTouchListener() {
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            return MainLayout.this.onContentTouch(v, event);
        }
    });

    // Initially hide the menu
    menu.setVisibility(View.GONE);
}

// Called from layout when this view should assign a size and position to each of its children
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    //Log.d("MainLayout.java onLayout()", "left " + left + " top " + top + " right " + right + " bottom " + bottom);
    //Log.d("MainLayout.java onLayout()", "getHeight " + this.getHeight() + " getWidth " + this.getWidth());

    // True if MainLayout 's size and position has changed
    // If true, calculate child views size
    if(changed) {
        // Note: LayoutParams are used by views to tell their parents how they want to be laid out

        //Log.d("MainLayout.java onLayout()", "changed " + changed);

        // content View occupies the full height and width
        LayoutParams contentLayoutParams = (LayoutParams)content.getLayoutParams();
        contentLayoutParams.height = this.getHeight();
        contentLayoutParams.width = this.getWidth();

        // menu View occupies the full height, but certain width
        LayoutParams menuLayoutParams = (LayoutParams)menu.getLayoutParams();
        menuLayoutParams.height = this.getHeight();
        menuLayoutParams.width = this.getWidth() - menuRightMargin;  
    }

    // Layout the child views    
    menu.layout(left, top, right - menuRightMargin, bottom);
    content.layout(left + contentXOffset, top, right + contentXOffset, bottom);

}

// Custom methods for MainLayout

// Used to show/hide menu accordingly
public void toggleMenu() {
    // Do nothing if sliding is in progress
    if(currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
        return;

    switch(currentMenuState) {
    case HIDDEN:
        currentMenuState = MenuState.SHOWING;
        menu.setVisibility(View.VISIBLE);
        menuScroller.startScroll(0, 0, menu.getLayoutParams().width,
                0, SLIDING_DURATION);
        break;
    case SHOWN:
        currentMenuState = MenuState.HIDING;
        menuScroller.startScroll(contentXOffset, 0, -contentXOffset, 
                0, SLIDING_DURATION);
        break;
    default:
        break;
    }

    // Begin querying
    menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);

    // Invalite this whole MainLayout, causing onLayout() to be called
    this.invalidate();
}

// Query Scroller
protected class MenuRunnable implements Runnable {
    @Override
    public void run() {
        boolean isScrolling = menuScroller.computeScrollOffset();
        adjustContentPosition(isScrolling);
    }
}

// Adjust content View position to match sliding animation
private void adjustContentPosition(boolean isScrolling) {
    int scrollerXOffset = menuScroller.getCurrX();

    //Log.d("MainLayout.java adjustContentPosition()", "scrollerOffset " + scrollerOffset);

    // Translate content View accordingly
    content.offsetLeftAndRight(scrollerXOffset - contentXOffset);

    contentXOffset = scrollerXOffset;

    // Invalite this whole MainLayout, causing onLayout() to be called
    this.invalidate();

    // Check if animation is in progress
    if (isScrolling)
        menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);
    else
        this.onMenuSlidingComplete();
}

// Called when sliding is complete
private void onMenuSlidingComplete() {
    switch (currentMenuState) {
    case SHOWING:
        currentMenuState = MenuState.SHOWN;
        break;
    case HIDING:
        currentMenuState = MenuState.HIDDEN;
        menu.setVisibility(View.GONE);
        break;
    default:
        return;
    }
}

// Make scrolling more natural. Move more quickly at the end
// See the formula here http://cyrilmottier.com/2012/05/22/the-making-of-prixing-fly-in-app-menu-part-1/
protected class EaseInInterpolator implements Interpolator {
    @Override
    public float getInterpolation(float t) {
        return (float)Math.pow(t-1, 5) + 1;
    }

}

// Is menu completely shown
public boolean isMenuShown() {
    return currentMenuState == MenuState.SHOWN;
}

// Handle touch event on content View
public boolean onContentTouch(View v, MotionEvent event) {
    // Do nothing if sliding is in progress
    if(currentMenuState == MenuState.HIDING || currentMenuState == MenuState.SHOWING)
        return false;

    // getRawX returns X touch point corresponding to screen
    // getX sometimes returns screen X, sometimes returns content View X
    int curX = (int)event.getRawX();
    int diffX = 0;

    switch(event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        //Log.d("MainLayout.java onContentTouch()", "Down x " + curX);

        prevX = curX;
        return true;

    case MotionEvent.ACTION_MOVE:
        //Log.d("MainLayout.java onContentTouch()", "Move x " + curX);

        // Set menu to Visible when user start dragging the content View
        if(!isDragging) {
            isDragging = true;
            menu.setVisibility(View.VISIBLE);
        }

        // How far we have moved since the last position
        diffX = curX - prevX;

        // Prevent user from dragging beyond border
        if(contentXOffset + diffX <= 0) {
            // Don't allow dragging beyond left border
            // Use diffX will make content cross the border, so only translate by -contentXOffset
            diffX = -contentXOffset;
        } else if(contentXOffset + diffX > mainLayoutWidth - menuRightMargin) {
            // Don't allow dragging beyond menu width
            diffX = mainLayoutWidth - menuRightMargin - contentXOffset;
        }

        // Translate content View accordingly
        content.offsetLeftAndRight(diffX);

        contentXOffset += diffX;

        // Invalite this whole MainLayout, causing onLayout() to be called
        this.invalidate();

        prevX = curX;
        lastDiffX = diffX;
        return true;

    case MotionEvent.ACTION_UP:
        //Log.d("MainLayout.java onContentTouch()", "Up x " + curX);

        Log.d("MainLayout.java onContentTouch()", "Up lastDiffX " + lastDiffX);

        // Start scrolling
        // Remember that when content has a chance to cross left border, lastDiffX is set to 0
        if(lastDiffX > 0) {
            // User wants to show menu
            currentMenuState = MenuState.SHOWING;

            // No need to set to Visible, because we have set to Visible in ACTION_MOVE
            //menu.setVisibility(View.VISIBLE);

            //Log.d("MainLayout.java onContentTouch()", "Up contentXOffset " + contentXOffset);

            // Start scrolling from contentXOffset
            menuScroller.startScroll(contentXOffset, 0, menu.getLayoutParams().width - contentXOffset,
                    0, SLIDING_DURATION);
        } else if(lastDiffX < 0) {
            // User wants to hide menu
            currentMenuState = MenuState.HIDING;
            menuScroller.startScroll(contentXOffset, 0, -contentXOffset, 
                    0, SLIDING_DURATION);
        }

        // Begin querying
        menuHandler.postDelayed(menuRunnable, QUERY_INTERVAL);

        // Invalite this whole MainLayout, causing onLayout() to be called
        this.invalidate();

        // Done dragging
        isDragging = false;
        prevX = 0;
        lastDiffX = 0;
        return true;

    default:
        break;
    }

    return false;
}

}

3 个答案:

答案 0 :(得分:1)

如果您想要居中一个项目,请不要使用LinearLayout,因为它们用于连续显示多个项目。

使用RelativeLayout而不是属性android:layout_centerInParent="true"

<!-- This holds our menu -->
 <RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"   
     >

    <ListView
        android:id="@+id/activity_main_menu_listview"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#ffffff"
        android:layout_centerInParent="true"
        android:divider="@android:color/transparent"
        android:cacheColorHint="#00000000" >
    </ListView>
</RelativeLayout>

答案 1 :(得分:0)

试试这个:

 <LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"   
    android:gravity="center_horizontal"
    android:orientation="vertical" >

并确保您的listview's项目布局也具有central重力。

我注意到您还使用了自定义viewcom.entropy.slidingmenu2.layout.MainLayout

如果它不起作用,请发布这两个代码。

答案 2 :(得分:0)

你有两个问题在继续。

  1. 您的父级LinearLayout是layout_width =“wrap_content”,这意味着它只需要远离屏幕左边缘,而不是一直到屏幕的右边缘,这就是你想要的。
  2. 您需要告诉您的孩子ListView(activity_main_menu_listview)水平居中。您需要的属性是layout_gravity,而不是gravity。 layout_gravity属性用于子视图,以说明其父视图中的位置。 gravity属性表示视图本身(通常是TextView)中的内容(通常是文本)应该去的位置。
  3. 所以你需要的是:

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"   
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/activity_main_menu_listview"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:background="#ffffff"
            android:divider="@android:color/transparent"
            android:cacheColorHint="#00000000" >
        </ListView>
    </LinearLayout>
    

    此外,还有一些非常小的要点:1)Google希望我们使用match_parent而不是fill_parent(历史上最愚蠢的弃用之一); 2)您只需要XML的根视图中的xmlns属性,而不是ListView的父级。