如何将视图添加到视图组?
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