Android Listview屏幕重心

标签 android android-layout layout

我想知道如何在 LinearLayout 中心调整我的 ListView activity_main_menu_listview。我尝试过重力但它对我不起作用但是当我给它 margin 时它就起作用了。但是我想要它自动,那我该怎么做呢? 谢谢

<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>

主要布局代码:

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;
}

最佳答案

如果您想将某个项目居中,请不要使用 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>

关于Android Listview屏幕重心,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26901161/

相关文章:

java - onActivityResult 之后值被设置为 null

java - 使用 android 获取 JSON 值

java - 在类或方法中放置变量的最佳位置 (Android Studio)

java - 不希望 Listactivity 的项目之间存在距离

html - MVC 中的布局在页面顶部留有空白

java - 如何制作一个永远不会选择两次相同图像的功能

android - 如何从单独的类中动态更改 ListView?

Android AdvancedRecyclerView SwitchButton 阻止点击进入父布局

java - 添加复选框后 Android 应用程序崩溃

layout - 布局/设计长而复杂的 Web 表单以收集用户输入的最佳方式是什么