Android版面 - 图像w alignParentBottom

时间:2016-01-08 20:09:09

标签: android android-layout

问题

在附带的屏幕截图中,底部(蓝色)图像下方有一小片橙色。因为图像/布局无法有效地与屏幕底部对齐。

注意:

Android Studio的布局管理器中,展示位置看起来是正确的,我只在实际 Android设备上看到此问题。

问题

我已经尝试设置margin& padding完成图像向下移动几个像素,但没有任何变化。如何让这个图像/相对布局与应用程序窗口的底部齐平?

featured.xml(查看)

<?xml version="1.0" encoding="utf-8"?>
<someco.android.phone.Featured xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:id="@+id/featuredLoaderContainer"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_marginBottom="52dp"
        android:layout_gravity="center_horizontal" />

    <someco.android.phone.FeaturedPager
       android:id="@+id/featuredPager"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:layout_gravity="center"
       android:layout_marginBottom="52dp" />

    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true" >

        <LinearLayout
            android:id="@+id/featuredWatchTextContainer"
            android:orientation="vertical"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true" >

            <TextView
                android:id="@+id/featuredDiscoverTxtView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/discover_lakewood"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="#FFFFFF"
                android:textSize="15sp" />

            <TextView
                android:id="@+id/featuredWatchTxtView"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/watch_announcements"
                android:textAppearance="?android:attr/textAppearanceMedium"
                android:textColor="#FDC99B"
                android:textSize="13sp" />

        </LinearLayout>

        <ImageView
            android:id="@+id/featuredWatchBtn"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/featuredWatchTextContainer"
            android:layout_marginLeft="20dp"
            android:src="@drawable/featured_watch" />

    </RelativeLayout>

    <RelativeLayout
        android:id="@+id/featuredOnlineContainer"
        android:layout_width="match_parent"
        android:layout_height="62dp"
        android:background="@drawable/featured_online_bg"
        android:layout_alignParentBottom="true">
        <!--android:visibility="gone">-->

        <!--x image-->
        <ImageView
            android:src="@drawable/featured_online_x"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentLeft="true"
            android:layout_alignParentBottom="true"/>

        <!-- in progress text-->
        <ImageView
            android:src="@drawable/featured_online_in_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentLeft="true"
            android:layout_marginLeft="82dp"
            android:paddingTop="7dp"
            />

        <!--join now text-->
        <ImageView
            android:src="@drawable/featured_online_join_now"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="51dp"
            android:paddingTop="7dp"/>

        <!--join now arrow-->
        <ImageView
            android:src="@drawable/featured_online_join_arrow"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerVertical="true"
            android:layout_alignParentRight="true"
            android:layout_marginRight="30dp"
            android:paddingTop="7dp"/>


    </RelativeLayout>

</someco.android.phone.Featured>

Featured.java(控制器)

package someco.android.phone;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Typeface;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.crashlytics.android.Crashlytics;
import com.google.android.gms.analytics.HitBuilders;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;

//import com.google.analytics.tracking.android.Fields;
//import com.google.analytics.tracking.android.MapBuilder;

public class Featured extends RelativeLayout {
    final static String FEATURED_FEED = "/_layouts/Helper.asmx/GetLiveAdSet";
    final static String FEATURED_VIDEO_FEED = "/_layouts/PortalAPI.asmx/GetCurrentInfo";
    // XML node tags
    final static String TAG_ADBIN = "AdBin";
    final static String TAG_URL_IMAGE = "MobileAd";
    final static String TAG_URL_LINK = "MobileURL";
    final static String TAG_RUNNING_TIME = "MobileRunningTime";
    final static String TAG_WEEKLY = "Weekly";
    final static String TAG_URL_VIDEO = "PreVideoURLNew";

    final static int DEFAULT_RUNNING_TIME = 7;

    public static Featured instance;
    ArrayList<GenericAsyncTask> mTasks = new ArrayList<GenericAsyncTask>();
    Date mLastCache;

    TextView discoverTxt;
    TextView watchTxt;
    ImageView watchBtn;
    RelativeLayout featuredOnlineChurchContainer;
    String videoUrl;
    CountDownTimer mTimer;

    FeaturedPager mPager;
    PagerAdapter mPagerAdapter;
    ArrayList<FeaturedTab> mTabs = new ArrayList<FeaturedTab>();
    int mSelectedPageIndex = 0;
    int mTabLoadedCount = 0;
    int mTabCount = 0;
    boolean mTabsLoaded = false;

    int mPageImageWidth;
    int mPageImageHeightMax;

    String className;

    public Featured(Context context, AttributeSet attrs) {
        super(context, attrs);
        Featured.instance = this;
        this.className = this.getClass().getSimpleName();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();

        /*
         * load the fonts that are going to be used with this view
         */
        Typeface museoSans500 = null;
        Typeface museoSans700 = null;

        if(!this.isInEditMode()) {
            MyApplication.instance.mTracker.setScreenName(className);
            MyApplication.instance.mTracker.send(new HitBuilders.ScreenViewBuilder().build());

            museoSans500 = Typeface.createFromAsset(getContext().getAssets(), "fonts/MuseoSans_500.otf");
            museoSans700 = Typeface.createFromAsset(getContext().getAssets(), "fonts/MuseoSans_700.otf");

            /*
             * start assigning layout elements to local variables
             */
                this.discoverTxt = (TextView) this.findViewById(R.id.featuredDiscoverTxtView);
                this.watchTxt = (TextView) this.findViewById(R.id.featuredWatchTxtView);
                this.watchBtn = (ImageView) this.findViewById(R.id.featuredWatchBtn);
                this.mPager = (FeaturedPager) this.findViewById(R.id.featuredPager);
                this.featuredOnlineChurchContainer = (RelativeLayout) this.findViewById(R.id.featuredOnlineChurchContainer);

            /*
             * Assign the fonts
             */
                this.discoverTxt.setTypeface(museoSans700);
                this.watchTxt.setTypeface(museoSans500);

                // calculate tab image width and max height
                int paddingPageWidthPixels = MyApplication.dp2px(14 * 2);
                int marginPageImageTopPixels = MyApplication.dp2px(42);
                int marginPageImageBottomPixels = MyApplication.dp2px(60);
                int marginImageShadowMargins = MyApplication.dp2px(25);
                //                      screen width - page margins (14dp x 2)
                this.mPageImageWidth = MyApplication.instance.width - paddingPageWidthPixels;
                this.mPageImageHeightMax = MyApplication.instance.height - marginPageImageTopPixels - marginPageImageBottomPixels - marginImageShadowMargins;

            // Set up pager objects
            mPager.setPagingEnabled(false);
            mPagerAdapter = new FeaturedPagerLoaderAdapter();
            mPager.setAdapter(mPagerAdapter);
            mSelectedPageIndex = 1;
            mPager.setCurrentItem(mSelectedPageIndex, false);

            mPager.setOnTouchListener(new OnTouchListener() {
                @Override
                public boolean onTouch(View v, MotionEvent event) {
                    if(mTimer != null) {
                        mTimer.cancel();
                    }
                    return false;
                }
            });

            // see if online church is playing
            final GenericAsyncTask onlineCallback = new GenericAsyncTask();
            onlineCallback.callback = new Runnable() {
                @Override
                public void run() {
                    try {
                        Boolean online = (Boolean)onlineCallback.result;

                        if (online) {
                            // make the Online Church button visible
                            featuredOnlineChurchContainer.setVisibility(View.VISIBLE);
                        }
                    } catch(Exception e) {
                        Crashlytics.logException(e);
                        e.printStackTrace();
                    }
                }
            };
            GenericAsyncTask onlineTask = OnlineChurch.isOnlineNow(onlineCallback);
            mTasks.add(onlineTask);

            // doesn't work because the image isn't on the stage just yet
//            //set online church bg to fit it's aspect ratio.
//            int w = this.featuredOnlineChurchContainer.getWidth();
//            int h = ((Double)(w * 0.2)).intValue();
//            this.featuredOnlineChurchContainer.getLayoutParams().height = h;
//            this.featuredOnlineChurchContainer.requestLayout();

            featuredOnlineChurchContainer.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // go to online church
                    Navigation.instance.onlineChurchBtn.callOnClick();
                }
            });

            mPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
                @Override
                public void onPageSelected(int position) {
                    super.onPageSelected(position);

                    mSelectedPageIndex = position;

                /*
                 * We are keeping a duplicate of a tab on either end and then when we get
                 * to the duplicates we are jumping to the opposite end so the user can
                 * continue scrolling in either direction in a seemingly infinite fashion.
                 *  -DJL
                 */

                    // if we are at the first left duplicate jump to the
                    // last tab before right duplication
                    if(mSelectedPageIndex == 0) {
                        mSelectedPageIndex = mTabs.size() - 2;
                    }
                    // if we are at the first right duplicate jump to
                    // the tab after the left duplication
                    if(mSelectedPageIndex == mTabs.size() - 1) {
                        mSelectedPageIndex = 1;
                    }
                }

                @Override
                public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
                    super.onPageScrolled(position, positionOffset, positionOffsetPixels);
                }

                @Override
                public void onPageScrollStateChanged(int state) {
                    super.onPageScrollStateChanged(state);

                    if (state == ViewPager.SCROLL_STATE_IDLE) {
                        mPager.setCurrentItem(mSelectedPageIndex, false);
                        setAdTimer();
                    }
                }
            });

            this.watchBtn.setOnClickListener(new View.OnClickListener() {
                public void onClick(View v) {
                    //MyApplication.instance.mGaTracker.sendEvent("ui_action", "button_press", className + ":watch_button", 0L);
//              MyApplication.instance.mGaTracker.send(MapBuilder
//                      .createEvent("ui_action", "button_press", className + ":watch_button", null)
//                      .build()
//                  );
                    MyApplication.instance.mTracker.send(new HitBuilders.EventBuilder()
                            .setCategory("ui_action")
                            .setAction("button_press")
                            .setLabel(className + ":watch_button")
                                    //.setValue()
                            .build());
                    if(videoUrl == null) {
                        getVideoXML(true);
                    } else {
                        MyApplication.instance.playVideo(getContext(), videoUrl);
                    }
                }
            });

            // load last cache date
            if(mLastCache == null) {
                long time = MyApplication.instance.mSharedPreferences.getLong(MyApplication.PREFS_KEY_FEATURED_LAST_CACHE, 0);
                if(time != 0) {
                    this.mLastCache = new Date(time);
                }
            }

            boolean shouldUseCache = true;
            if(mLastCache != null) {
                // Get the date for midnight or noon thirty US/Central (Houston, Texas) time. -DJL
                Date cacheCheck = Utils.twiceDailyCacheDate();
                // use the cache if it is fresh or if there is no network connectivity
                shouldUseCache = mLastCache.after(cacheCheck) || !MyApplication.isConnected(getContext());
            }

            if(shouldUseCache) {
                // get the xml from cache if present
                String xml = MainActivity.getXmlFromCache(XMLParser.prependHost(Featured.FEATURED_FEED));
                if(xml != null) {
                    this.parseXML(xml);
                    this.getVideoXML(false);
                    return;
                }
            }

            if(!MyApplication.isConnected(getContext())){
                ContentContainer.instance.noInternetRefresh();
                ((FeaturedPagerLoaderAdapter) this.mPagerAdapter).loaderOff();
                MyApplication.instance.dialogNoCache(getContext());
            }

            // get the Featured XML
            final GenericAsyncTask fxcallback = new GenericAsyncTask();
//            fxcallback.background = new Runnable() {
//                public void run() {
//                    task.result = XMLParser.getXMLFromURLPost(XMLParser.prependHost(Featured.FEATURED_FEED));
//                }
//            };
            fxcallback.callback = new Runnable() {
                public void run() {
                    String xml = null;
                    if(fxcallback.result == null || fxcallback.result.toString().length() == 0) {
                        MyApplication.instance.dialogServerError(MainActivity.instance);
                    } else {
                        xml = fxcallback.result.toString();
                        MainActivity.addXmlToCache(XMLParser.prependHost(Featured.FEATURED_FEED), xml);
                        // save cache date
                        SharedPreferences.Editor editor = MyApplication.instance.mSharedPreferences.edit();
                        editor.putLong(MyApplication.PREFS_KEY_FEATURED_LAST_CACHE, (new Date()).getTime());
                        editor.commit();
                    }
                    parseXML(xml);
                }
            };
//            task.execute();
            GenericAsyncTask fxTask = XMLParser.getXMLFromURLPost(XMLParser.prependHost(Featured.FEATURED_FEED), fxcallback);
            mTasks.add(fxTask);

            this.getVideoXML(false);
        }
    }

    private void parseXML(final String xml) {
        final GenericAsyncTask task = new GenericAsyncTask();
        task.background = new Runnable() {
            public void run() {
                Document doc = XMLParser.getDOM(xml);
                if(doc == null) {
                    return;
                }

                NodeList featuredNodes = doc.getElementsByTagName(Featured.TAG_ADBIN);
                mTabCount = featuredNodes.getLength(); // The number of duplicate tabs we are adding

                // loop through all featured nodes <AdBin>
                LayoutInflater inflater = LayoutInflater.from(getContext());

                for (int i = 0; i < featuredNodes.getLength(); i++) {
                    Element element = (Element)featuredNodes.item(i);
                    String imageUrl = XMLParser.getValue(element, Featured.TAG_URL_IMAGE);
                    String linkUrl = XMLParser.getValue(element, Featured.TAG_URL_LINK);
                    String time = XMLParser.getValue(element, Featured.TAG_RUNNING_TIME);
                    int runningTime = Integer.parseInt(time);
                    if(runningTime <= 0) {
                        runningTime = Featured.DEFAULT_RUNNING_TIME;
                    }
                    // convert to milliseconds
                    runningTime *= 1000;

                    URL url = null;
                    try {
                        url = new URL(imageUrl);
                    } catch (MalformedURLException e) {
                        e.printStackTrace();
                    }

                    if(imageUrl != null && imageUrl.length() > 0 && url != null) {
                        // If we got here then we pulled a new featured XML and need to make
                        // sure we are using up to date featured images as well -DJL
                        MainActivity.removeBitmapFromCache(imageUrl);
                        FeaturedTab tab = (FeaturedTab)inflater.inflate(R.layout.featured_tab, Featured.this, false);
                        tab.setData(linkUrl, imageUrl, runningTime);
                        mTabs.add(tab);
                    } else {
                        tabFinishedLoading();
                    }
                }
            }
        };
        task.callback = new Runnable() {
            public void run() {}
        };
        task.execute();
        mTasks.add(task);
    }

    public void tabFinishedLoading() {
        mTabLoadedCount++;
        if(mTabLoadedCount == mTabCount) {
            MainActivity.instance.runOnUiThread(new Runnable() {
                public void run() { 
                    /*
                     * We are keeping duplicate of a tab on either end and then when we get 
                     * to the duplicates we are jumping to the opposite end so the user can
                     * continue scrolling in either direction in a seemingly infinite fashion.
                     *  -DJL
                     */

                    // duplication and insertion for infinite paging
                    if(mTabs.size() == 1) {
                        while(mTabs.size() < 3) {
                            mTabs.add(mTabs.get(0).duplicate());
                        }
                    } else {
                        if(mTabs.size() != 0) {
                            int last = mTabs.size() - 1;
                            FeaturedTab posFirst = mTabs.get(last).duplicate();
                            FeaturedTab posLast = mTabs.get(0).duplicate();
                            mTabs.add(0, posFirst);
                            mTabs.add(posLast);
                        }
                    }

                    mPagerAdapter = new FeaturedPagerAdapter(mTabs);
                    mPager.setAdapter(mPagerAdapter);
                    mSelectedPageIndex = 1;
                    mPager.setCurrentItem(mSelectedPageIndex, false);

                    for(FeaturedTab tab : mTabs) {
                        if(tab != null) {
                            tab.clearLoader();
                        }
                    }

                    mTabsLoaded = true;
                    mPager.setPagingEnabled(true);
                    setAdTimer();
                }
            });     
        }
    }

    public void removeTab(FeaturedTab tab) {
        mTabs.remove(tab);
    }

    private void getVideoXML(boolean open) {
        final boolean shouldOpen = open;
        // get the Featured Video XML
        String videoXml = MainActivity.getXmlFromCache(XMLParser.prependHost(Featured.FEATURED_VIDEO_FEED));
        if(videoXml != null) {
            this.parseVideoXML(videoXml, shouldOpen);
            return;
        }

        final GenericAsyncTask task = new GenericAsyncTask();
        task.background = new Runnable() {
            public void run() {
                task.result = XMLParser.getXMLFromURLPost(XMLParser.prependHost(Featured.FEATURED_VIDEO_FEED));
            }
        };
        task.callback = new Runnable() {
            public void run() {
                String videoXml = null;
                if(task.result == null || task.result.toString().length() == 0) {
                    MyApplication.instance.dialogServerError(MainActivity.instance);
                } else {
                    videoXml = task.result.toString();
                    MainActivity.addXmlToCache(XMLParser.prependHost(Featured.FEATURED_VIDEO_FEED), videoXml);
                }
                parseVideoXML(videoXml, shouldOpen);
            }
        };
        task.execute();
        mTasks.add(task);
    }

    private void parseVideoXML(String xml, boolean open) {
        Document doc = XMLParser.getDOM(xml);
        if(doc != null) {
            NodeList nodes = doc.getElementsByTagName(Featured.TAG_WEEKLY);
            Element element = (Element)nodes.item(0);
//          this.videoUrl = MyApplication.URL_MEDIA + XMLParser.getValue(element, Featured.TAG_URL_VIDEO);
            this.videoUrl = XMLParser.getValue(element, Featured.TAG_URL_VIDEO); // for the new url it comes absolute
        }

        if(open) {
            MyApplication.instance.playVideo(this.getContext(), videoUrl);      
        }
    }

    private void setAdTimer() {
        if(!mTabsLoaded) {
            return;
        }

        if(this.mTimer != null) {
            this.mTimer.cancel();
        }
        if(mTabs.size() < mSelectedPageIndex) {
            return;
        }
        FeaturedTab current = mTabs.get(mSelectedPageIndex);
        if(current != null) {
            this.mTimer = new CountDownTimer(current.getRunningTime(), 1000) {
                 public void onTick(long millisUntilFinished) {}
                 public void onFinish() {
                     cycle();
                 }
            }.start();
        }
    }

    public void cycle() {
        mPager.setCurrentItem(mSelectedPageIndex + 1, true);
        this.setAdTimer();
    }

     private void cancelTasks() {
         for(GenericAsyncTask task : mTasks) {
             task.cancel(true);
         }
         mTasks.clear();
     }

    @Override
    protected void onDetachedFromWindow() {
        this.cancelTasks();
        this.mTabs.clear();

        this.mPager.setAdapter(null);
        this.mPagerAdapter = null;      

        if(this.mTimer != null) {
            this.mTimer.cancel();
        }
        Featured.instance = null;
        super.onDetachedFromWindow();
    };

    static public class FeaturedPagerAdapter extends PagerAdapter {
        ArrayList<FeaturedTab> mPages;

        public FeaturedPagerAdapter(ArrayList<FeaturedTab> pages) {
            super();
            mPages = pages;
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            FeaturedTab tab = mPages.get(position);
            if(tab != null) {
                container.addView(tab);
            }
            return tab;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View)object);
        }

        @Override
        public int getCount() {
            return mPages.size();
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return (view == object);
        }
    }
    static public class FeaturedPagerLoaderAdapter extends PagerAdapter {
        FeaturedTab mLoadPage;

        public FeaturedPagerLoaderAdapter() {
            super();
            LayoutInflater inflater = LayoutInflater.from(Featured.instance.getContext());
            mLoadPage = (FeaturedTab)inflater.inflate(R.layout.featured_tab, Featured.instance, false);
        }

        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(mLoadPage);
            return mLoadPage;
        }

        @Override
        public void destroyItem(ViewGroup container, int position, Object object) {
            container.removeView((View)object);
        }

        @Override
        public int getCount() {
            return 1;
        }

        @Override
        public boolean isViewFromObject(View view, Object object) {
            return (view == object);
        }

        public void loaderOff() {
            mLoadPage.mProgressBar.setVisibility(View.INVISIBLE);
        }
    }
}

设备屏幕截图

Android Layout Screen

抽拉/ featured_online_bg

Layout Background

1 个答案:

答案 0 :(得分:0)

这个问题的新细节引出了我的答案。我本来会关闭这个问题,但是我发现了一些有用的东西,所以为了记录起见,我将把它们留在这里。

怪异

根据我的情况,当设置layout_alignParentBottom时,marginTop不适用于任何值。我必须使用带有负值的layout_marginBottom

我的解决方案

我发现在此布局之外有许多父容器,并且此布局已加载到那里。我不得不对其中的一些进行测试clipChildren="false",但我终于找到了导致问题的原因。所以这是剪辑儿童和布局边距的组合导致了我的问题。

希望有人能从我失去的时间中获益