如何将视图添加到视图组?

Posted

技术标签:

【中文标题】如何将视图添加到视图组?【英文标题】:how to add view to viewgroup? 【发布时间】:2012-01-11 12:36:48 【问题描述】:

我的 SD 卡上有一张相机拍摄的位图。我创建了一个视图组,我将其设置为我的活动的视图。我想以编程方式创建一个视图,并将位图设置为视图,然后将视图添加到视图组并显示。除了位图没有显示而是黑屏之外,一切似乎都正常工作。我检查了位图是否不为空并且视图组的子数不为零。谢谢马特

 @Override 
        public void onCreate(Bundle savedInstanceState) 
            super.onCreate(savedInstanceState);

            requestWindowFeature(Window.FEATURE_NO_TITLE);
            getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                    WindowManager.LayoutParams.FLAG_FULLSCREEN);

            setContentView(R.layout.hpview);
            final ViewGroup viewgroup = (ViewGroup)findViewById(R.id.hpview); 






            tempFile = new File(Environment.getExternalStorageDirectory().
                    getAbsolutePath() + "/"+"image.jpeg");

            imageArray = new byte[(int)tempFile.length()];





         try

                InputStream is = new FileInputStream(tempFile);
                BufferedInputStream bis = new BufferedInputStream(is);
                DataInputStream dis = new DataInputStream(bis);


                int i = 0;

                while (dis.available() > 0 ) 
                imageArray[i] = dis.readByte();
                i++;
                

                dis.close();


            catch (Exception e) 

                   e.printStackTrace();
                



           Bitmap bm = BitmapFactory.decodeByteArray(imageArray, 0, imageArray.length);

            if(bm == null)
                Log.e(TAG, "bm = null");
            else
                Log.e(TAG, "bm =  not null");
            




            Paint pTouch = new Paint(Paint.ANTI_ALIAS_FLAG);         

             Canvas canvas = new Canvas();
             Log.e(TAG, "canvas created");

             canvas.drawBitmap(bm, 10, 10, pTouch);
             Log.e(TAG, "canvas drawn bm");

             View view = new View(this);
             Log.e(TAG, "view created");


             viewgroup.addView(view);
             Log.e(TAG, "view added to viewgroup");

             viewgroup.bringChildToFront(view);
             viewgroup.postInvalidate();
             Log.e(TAG, "post inval called on viewgroup");

             Log.e(TAG, "no of chidren = "+viewgroup.getChildCount());

     

.

01-11 12:35:03.747: ERROR/*********entryscreen(5179): clicked slide
01-11 12:35:03.747: INFO/ActivityManager(1900): Starting activity: Intent  cmp=com.tecmark/.HorizontalPagerActivity 
01-11 12:35:03.767: ERROR/*********horizontalpager(5179): inside hp constructor for xml inflation
01-11 12:35:03.772: INFO/global(5179): Default buffer size used in BufferedInputStream constructor. It would be better to be explicit if an 8k buffer is required.
01-11 12:35:03.952: DEBUG/dalvikvm(5179): GC freed 1172 objects / 92200 bytes in 65ms
01-11 12:35:03.982: ERROR/*********hpActivity(5179): bm =  not null
01-11 12:35:03.982: ERROR/*********hpActivity(5179): canvas created
01-11 12:35:03.982: ERROR/*********hpActivity(5179): canvas drawn bm
01-11 12:35:03.982: ERROR/*********hpActivity(5179): view created
01-11 12:35:03.982: ERROR/*********hpActivity(5179): view added to viewgroup
01-11 12:35:03.982: ERROR/*********hpActivity(5179): post inval called on viewgroup
01-11 12:35:03.982: ERROR/*********hpActivity(5179): no of chidren = 1

[编辑]

/**
 * A view group that allows users to switch between multiple screens (layouts) in the same way as
 * the android home screen (Launcher application).
 * <p>
 * You can add and remove views using the normal methods @link ViewGroup#addView(View),
 * @link ViewGroup#removeView(View) etc. You may want to listen for updates by calling
 * @link HorizontalPager#setOnScreenSwitchListener(OnScreenSwitchListener) in order to perform
 * operations once a new screen has been selected.
 *
 * Modifications from original version (ysamlan): Animate argument in setCurrentScreen and duration
 * in snapToScreen; onInterceptTouchEvent handling to support nesting a vertical Scrollview inside
 * the RealViewSwitcher; allowing snapping to a view even during an ongoing scroll; snap to
 * next/prev view on 25% scroll change; density-independent swipe sensitivity; width-independent
 * pager animation durations on scrolling to properly handle large screens without excessively
 * long animations.
 *
 * Other modifications:
 * (aveyD) Handle orientation changes properly and fully snap to the right position.
 *
 * @author Marc Reichelt, <a href="http://www.marcreichelt.de/">http://www.marcreichelt.de/</a>
 * @version 0.1.0
 */
public final class HorizontalPager extends ViewGroup 
    /*
     * How long to animate between screens when programmatically setting with setCurrentScreen using
     * the animate parameter
     */
    private static final int ANIMATION_SCREEN_SET_DURATION_MILLIS = 500;
    // What fraction (1/x) of the screen the user must swipe to indicate a page change
    private static final int FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE = 4;
    private static final int INVALID_SCREEN = -1;
    /*
     * Velocity of a swipe (in density-independent pixels per second) to force a swipe to the
     * next/previous screen. Adjusted into mDensityAdjustedSnapVelocity on init.
     */
    private static final int SNAP_VELOCITY_DIP_PER_SECOND = 600;
    // Argument to getVelocity for units to give pixels per second (1 = pixels per millisecond).
    private static final int VELOCITY_UNIT_PIXELS_PER_SECOND = 1000;

    private static final int TOUCH_STATE_REST = 0;
    private static final int TOUCH_STATE_HORIZONTAL_SCROLLING = 1;
    private static final int TOUCH_STATE_VERTICAL_SCROLLING = -1;
    private int mCurrentScreen;
    private int mDensityAdjustedSnapVelocity;
    private boolean mFirstLayout = true;
    private float mLastMotionX;
    private float mLastMotionY;
    private OnScreenSwitchListener mOnScreenSwitchListener;
    private int mMaximumVelocity;
    private int mNextScreen = INVALID_SCREEN;
    private Scroller mScroller;
    private int mTouchSlop;
    private int mTouchState = TOUCH_STATE_REST;
    private VelocityTracker mVelocityTracker;
    private int mLastSeenLayoutWidth = -1;
    private static final String TAG = "*********horizontalpager";

    /**
     * Simple constructor to use when creating a view from code.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     */
    public HorizontalPager(final Context context) 
        super(context);
        Log.e(TAG, "inside hp standard constructor");
        init();
    

    /**
     * Constructor that is called when inflating a view from XML. This is called
     * when a view is being constructed from an XML file, supplying attributes
     * that were specified in the XML file. This version uses a default style of
     * 0, so the only attribute values applied are those in the Context's Theme
     * and the given AttributeSet.
     *
     * <p>
     * The method onFinishInflate() will be called after all children have been
     * added.
     *
     * @param context The Context the view is running in, through which it can
     *        access the current theme, resources, etc.
     * @param attrs The attributes of the XML tag that is inflating the view.
     * @see #View(Context, AttributeSet, int)
     */
    public HorizontalPager(final Context context, final AttributeSet attrs) 
        super(context, attrs);
        Log.e(TAG, "inside hp constructor for xml inflation");
        init();
    

    /**
     * Sets up the scroller and touch/fling sensitivity parameters for the pager.
     */
    private void init() 
        mScroller = new Scroller(getContext());

        // Calculate the density-dependent snap velocity in pixels
        DisplayMetrics displayMetrics = new DisplayMetrics();
        ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay()
                .getMetrics(displayMetrics);
        mDensityAdjustedSnapVelocity =
                (int) (displayMetrics.density * SNAP_VELOCITY_DIP_PER_SECOND);

        final ViewConfiguration configuration = ViewConfiguration.get(getContext());
        mTouchSlop = configuration.getScaledTouchSlop();
        mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
    

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) 
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int width = MeasureSpec.getSize(widthMeasureSpec);
        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        if (widthMode != MeasureSpec.EXACTLY) 
            throw new IllegalStateException("ViewSwitcher can only be used in EXACTLY mode.");
        

        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        if (heightMode != MeasureSpec.EXACTLY) 
            throw new IllegalStateException("ViewSwitcher can only be used in EXACTLY mode.");
        

        // The children are given the same width and height as the workspace
        final int count = getChildCount();
        for (int i = 0; i < count; i++) 
            getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);
        

        if (mFirstLayout) 
            scrollTo(mCurrentScreen * width, 0);
            mFirstLayout = false;
        

        else if (width != mLastSeenLayoutWidth)  // Width has changed
            /*
             * Recalculate the width and scroll to the right position to be sure we're in the right
             * place in the event that we had a rotation that didn't result in an activity restart
             * (code by aveyD). Without this you can end up between two pages after a rotation.
             */
            Display display =
                    ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE))
                            .getDefaultDisplay();
            int displayWidth = display.getWidth();

            mNextScreen = Math.max(0, Math.min(getCurrentScreen(), getChildCount() - 1));
            final int newX = mNextScreen * displayWidth;
            final int delta = newX - getScrollX();

            mScroller.startScroll(getScrollX(), 0, delta, 0, 0);
        

        mLastSeenLayoutWidth   = width;
    

    @Override
    protected void onLayout(final boolean changed, final int l, final int t, final int r,
            final int b) 
        int childLeft = 0;
        final int count = getChildCount();

        for (int i = 0; i < count; i++) 
            final View child = getChildAt(i);
            if (child.getVisibility() != View.GONE) 
                final int childWidth = child.getMeasuredWidth();
                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
                childLeft += childWidth;
            
        
    

    @Override
    public boolean onInterceptTouchEvent(final MotionEvent ev) 
        /*
         * By Yoni Samlan: Modified onInterceptTouchEvent based on standard ScrollView's
         * onIntercept. The logic is designed to support a nested vertically scrolling view inside
         * this one; once a scroll registers for X-wise scrolling, handle it in this view and don't
         * let the children, but once a scroll registers for y-wise scrolling, let the children
         * handle it exclusively.
         */
        final int action = ev.getAction();
        boolean intercept = false;

        switch (action) 
            case MotionEvent.ACTION_MOVE:
                /*
                 * If we're in a horizontal scroll event, take it (intercept further events). But if
                 * we're mid-vertical-scroll, don't even try; let the children deal with it. If we
                 * haven't found a scroll event yet, check for one.
                 */
                if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) 
                    /*
                     * We've already started a horizontal scroll; set intercept to true so we can
                     * take the remainder of all touch events in onTouchEvent.
                     */
                    intercept = true;
                 else if (mTouchState == TOUCH_STATE_VERTICAL_SCROLLING) 
                    // Let children handle the events for the duration of the scroll event.
                    intercept = false;
                 else  // We haven't picked up a scroll event yet; check for one.

                    /*
                     * If we detected a horizontal scroll event, start stealing touch events (mark
                     * as scrolling). Otherwise, see if we had a vertical scroll event -- if so, let
                     * the children handle it and don't look to intercept again until the motion is
                     * done.
                     */

                    final float x = ev.getX();
                    final int xDiff = (int) Math.abs(x - mLastMotionX);
                    boolean xMoved = xDiff > mTouchSlop;

                    if (xMoved) 
                        // Scroll if the user moved far enough along the X axis
                        mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
                        mLastMotionX = x;
                    

                    final float y = ev.getY();
                    final int yDiff = (int) Math.abs(y - mLastMotionY);
                    boolean yMoved = yDiff > mTouchSlop;

                    if (yMoved) 
                        mTouchState = TOUCH_STATE_VERTICAL_SCROLLING;
                    
                

                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                // Release the drag.
                mTouchState = TOUCH_STATE_REST;
                break;
            case MotionEvent.ACTION_DOWN:
                /*
                 * No motion yet, but register the coordinates so we can check for intercept at the
                 * next MOVE event.
                 */
                mLastMotionY = ev.getY();
                mLastMotionX = ev.getX();
                break;
            default:
                break;
            

        return intercept;
    

    @Override
    public boolean onTouchEvent(final MotionEvent ev) 

        if (mVelocityTracker == null) 
            mVelocityTracker = VelocityTracker.obtain();
        
        mVelocityTracker.addMovement(ev);

        final int action = ev.getAction();
        final float x = ev.getX();

        switch (action) 
            case MotionEvent.ACTION_DOWN:
                /*
                 * If being flinged and user touches, stop the fling. isFinished will be false if
                 * being flinged.
                 */
                if (!mScroller.isFinished()) 
                    mScroller.abortAnimation();
                

                // Remember where the motion event started
                mLastMotionX = x;

                if (mScroller.isFinished()) 
                    mTouchState = TOUCH_STATE_REST;
                 else 
                    mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
                

                break;
            case MotionEvent.ACTION_MOVE:
                final int xDiff = (int) Math.abs(x - mLastMotionX);
                boolean xMoved = xDiff > mTouchSlop;

                if (xMoved) 
                    // Scroll if the user moved far enough along the X axis
                    mTouchState = TOUCH_STATE_HORIZONTAL_SCROLLING;
                

                if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) 
                    // Scroll to follow the motion event
                    final int deltaX = (int) (mLastMotionX - x);
                    mLastMotionX = x;
                    final int scrollX = getScrollX();

                    if (deltaX < 0) 
                        if (scrollX > 0) 
                            scrollBy(Math.max(-scrollX, deltaX), 0);
                        
                     else if (deltaX > 0) 
                        final int availableToScroll =
                                getChildAt(getChildCount() - 1).getRight() - scrollX - getWidth();

                        if (availableToScroll > 0) 
                            scrollBy(Math.min(availableToScroll, deltaX), 0);
                        
                    
                

                break;

            case MotionEvent.ACTION_UP:
                if (mTouchState == TOUCH_STATE_HORIZONTAL_SCROLLING) 
                    final VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(VELOCITY_UNIT_PIXELS_PER_SECOND,
                            mMaximumVelocity);
                    int velocityX = (int) velocityTracker.getXVelocity();

                    if (velocityX > mDensityAdjustedSnapVelocity && mCurrentScreen > 0) 
                        // Fling hard enough to move left
                        snapToScreen(mCurrentScreen - 1);
                     else if (velocityX < -mDensityAdjustedSnapVelocity
                            && mCurrentScreen < getChildCount() - 1) 
                        // Fling hard enough to move right
                        snapToScreen(mCurrentScreen + 1);
                     else 
                        snapToDestination();
                    

                    if (mVelocityTracker != null) 
                        mVelocityTracker.recycle();
                        mVelocityTracker = null;
                    
                

                mTouchState = TOUCH_STATE_REST;

                break;
            case MotionEvent.ACTION_CANCEL:
                mTouchState = TOUCH_STATE_REST;
                break;
            default:
                break;
        

        return true;
    

    @Override
    public void computeScroll() 
        if (mScroller.computeScrollOffset()) 
            scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
            postInvalidate();
         else if (mNextScreen != INVALID_SCREEN) 
            mCurrentScreen = Math.max(0, Math.min(mNextScreen, getChildCount() - 1));

            // Notify observer about screen change
            if (mOnScreenSwitchListener != null) 
                mOnScreenSwitchListener.onScreenSwitched(mCurrentScreen);
            

            mNextScreen = INVALID_SCREEN;
        
    

    /**
     * Returns the index of the currently displayed screen.
     *
     * @return The index of the currently displayed screen.
     */
    public int getCurrentScreen() 
        return mCurrentScreen;
    

    /**
     * Sets the current screen.
     *
     * @param currentScreen The new screen.
     * @param animate True to smoothly scroll to the screen, false to snap instantly
     */
    public void setCurrentScreen(final int currentScreen, final boolean animate) 
        mCurrentScreen = Math.max(0, Math.min(currentScreen, getChildCount() - 1));
        if (animate) 
            snapToScreen(currentScreen, ANIMATION_SCREEN_SET_DURATION_MILLIS);
         else 
            scrollTo(mCurrentScreen * getWidth(), 0);
        
        invalidate();
    

    /**
     * Sets the @link OnScreenSwitchListener.
     *
     * @param onScreenSwitchListener The listener for switch events.
     */
    public void setOnScreenSwitchListener(final OnScreenSwitchListener onScreenSwitchListener) 
        mOnScreenSwitchListener = onScreenSwitchListener;
    

    /**
     * Snaps to the screen we think the user wants (the current screen for very small movements; the
     * next/prev screen for bigger movements).
     */
    private void snapToDestination() 
        final int screenWidth = getWidth();
        int scrollX = getScrollX();
        int whichScreen = mCurrentScreen;
        int deltaX = scrollX - (screenWidth * mCurrentScreen);

        // Check if they want to go to the prev. screen
        if ((deltaX < 0) && mCurrentScreen != 0
                && ((screenWidth / FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE) < -deltaX)) 
            whichScreen--;
            // Check if they want to go to the next screen
         else if ((deltaX > 0) && (mCurrentScreen + 1 != getChildCount())
                && ((screenWidth / FRACTION_OF_SCREEN_WIDTH_FOR_SWIPE) < deltaX)) 
            whichScreen++;
        

        snapToScreen(whichScreen);
    

    /**
     * Snap to a specific screen, animating automatically for a duration proportional to the
     * distance left to scroll.
     *
     * @param whichScreen Screen to snap to
     */
    private void snapToScreen(final int whichScreen) 
        snapToScreen(whichScreen, -1);
    

    /**
     * Snaps to a specific screen, animating for a specific amount of time to get there.
     *
     * @param whichScreen Screen to snap to
     * @param duration -1 to automatically time it based on scroll distance; a positive number to
     *            make the scroll take an exact duration.
     */
    private void snapToScreen(final int whichScreen, final int duration) 
        /*
         * Modified by Yoni Samlan: Allow new snapping even during an ongoing scroll animation. This
         * is intended to make HorizontalPager work as expected when used in conjunction with a
         * RadioGroup used as "tabbed" controls. Also, make the animation take a percentage of our
         * normal animation time, depending how far they've already scrolled.
         */
        mNextScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));
        final int newX = mNextScreen * getWidth();
        final int delta = newX - getScrollX();

        if (duration < 0) 
             // E.g. if they've scrolled 80% of the way, only animation for 20% of the duration
            mScroller.startScroll(getScrollX(), 0, delta, 0, (int) (Math.abs(delta)
                    / (float) getWidth() * ANIMATION_SCREEN_SET_DURATION_MILLIS));
         else 
            mScroller.startScroll(getScrollX(), 0, delta, 0, duration);
        

        invalidate();
    

    /**
     * Listener for the event that the HorizontalPager switches to a new view.
     */
    public static interface OnScreenSwitchListener 
        /**
         * Notifies listeners about the new screen. Runs after the animation completed.
         *
         * @param screen The new screen index.
         */
        void onScreenSwitched(int screen);
    

    @Override
    public void onDraw(Canvas canvas)
        super.onDraw(canvas);
        Log.e(TAG, "inside hp ondraw()");

    



【问题讨论】:

【参考方案1】:

尝试将 layoutparams 添加到保存位图的视图中

LayoutParams lp = new LayoutParams(LayoutParam.FILL_PARENT,
        LayoutParam.FILL_PARENT);
view.setLayoutParams(lp);

【讨论】:

您好,我很害怕。我还添加了 view.draw(canvas); 为什么不直接创建一个视图。并使用代码 view.setBackgroundDrawable(new BitmapDrawable(bm)); 我找到了生成幻灯片的代码,可能就像您网站上的那样;)它是一个在视图之间切换的视图组,我需要提供视图。谢谢 @turtleboy 你能告诉我你在哪里找到生成幻灯片的代码吗?我在找这样的东西很久了。 @Gabrielle 我在这里找到了来源。它与上面发布的相同。 github.com/ysamlan/horizontalpager/blob/master/src/com/github/…

以上是关于如何将视图添加到视图组?的主要内容,如果未能解决你的问题,请参考以下文章

无法将空子视图添加到视图组 Nativescript-Vue

将复选框动态添加到列表视图

动态添加视图并调整父视图组的大小

如何将代码隐藏页面添加到视图或部分视图

如何将 UIPanGestureRecognizer 添加到 UIScrollView 子视图

如何将固定高度视图添加到垂直堆栈视图?