首页dialog广告轮播
先上效果图(点击图片可以跳转相应webview)
1.添加Glide依赖
implementation 'com.github.bumptech.glide:glide:3.7.0'
2.创建工具类
2.1创建CircleFlowIndicator工具类
package com.example.test.util; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint.Style; import android.os.AsyncTask; import android.util.AttributeSet; import android.view.View; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.AnimationUtils; import com.example.test.R; public class CircleFlowIndicator extends View implements FlowIndicator, AnimationListener { private static final int STYLE_STROKE = 0; private static final int STYLE_FILL = 1; private float radius = 4; private float circleSeparation = 2*radius+radius; private float activeRadius = 0.5f; private int fadeOutTime = 0; private final Paint mPaintInactive = new Paint(Paint.ANTI_ALIAS_FLAG); private final Paint mPaintActive = new Paint(Paint.ANTI_ALIAS_FLAG); private ViewFlow viewFlow; private int currentScroll = 0; private int flowWidth = 0; private FadeTimer timer; public AnimationListener animationListener = this; private Animation animation; private boolean mCentered = false; /** * Default constructor * * @param context */ public CircleFlowIndicator(Context context) { super(context); initColors(0xFFFFFFFF, 0xFFFFFFFF, STYLE_FILL, STYLE_STROKE); } /** * The contructor used with an inflater * * @param context * @param attrs */ public CircleFlowIndicator(Context context, AttributeSet attrs) { super(context, attrs); // Retrieve styles attributs TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleFlowIndicator); // Gets the inactive circle type, defaulting to "fill" int activeType = a.getInt(R.styleable.CircleFlowIndicator_activeType, STYLE_FILL); int activeDefaultColor = 0xFFFFFFFF; // Get a custom inactive color if there is one int activeColor = a .getColor(R.styleable.CircleFlowIndicator_activeColor, activeDefaultColor); // Gets the inactive circle type, defaulting to "stroke" int inactiveType = a.getInt( R.styleable.CircleFlowIndicator_inactiveType, STYLE_STROKE); int inactiveDefaultColor = 0x44FFFFFF; // Get a custom inactive color if there is one int inactiveColor = a.getColor( R.styleable.CircleFlowIndicator_inactiveColor, inactiveDefaultColor); // Retrieve the radius radius = a.getDimension(R.styleable.CircleFlowIndicator_radius, 4.0f); circleSeparation = a.getDimension(R.styleable.CircleFlowIndicator_circleSeparation, 2*radius+radius); activeRadius = a.getDimension(R.styleable.CircleFlowIndicator_activeRadius, 0.5f); // Retrieve the fade out time fadeOutTime = a.getInt(R.styleable.CircleFlowIndicator_fadeOut, 0); mCentered = a.getBoolean(R.styleable.CircleFlowIndicator_centered, false); initColors(activeColor, inactiveColor, activeType, inactiveType); } private void initColors(int activeColor, int inactiveColor, int activeType, int inactiveType) { // Select the paint type given the type attr switch (inactiveType) { case STYLE_FILL: mPaintInactive.setStyle(Style.FILL); break; default: mPaintInactive.setStyle(Style.STROKE); } mPaintInactive.setColor(inactiveColor); // Select the paint type given the type attr switch (activeType) { case STYLE_STROKE: mPaintActive.setStyle(Style.STROKE); break; default: mPaintActive.setStyle(Style.FILL); } mPaintActive.setColor(activeColor); } /* * (non-Javadoc) * * @see android.view.View#onDraw(android.graphics.Canvas) */ @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); int count = 3; if (viewFlow != null) { count = viewFlow.getViewsCount(); } //this is the amount the first circle should be offset to make the entire thing centered float centeringOffset = 0; int leftPadding = getPaddingLeft(); // Draw stroked circles for (int iLoop = 0; iLoop < count; iLoop++) { canvas.drawCircle(leftPadding + radius + (iLoop * circleSeparation) + centeringOffset, getPaddingTop() + radius, radius, mPaintInactive); } float cx = 0; if (flowWidth != 0) { // Draw the filled circle according to the current scroll cx = (currentScroll * circleSeparation) / flowWidth; } // The flow width has been upadated yet. Draw the default position canvas.drawCircle(leftPadding + radius + cx+centeringOffset, getPaddingTop() + radius, radius + activeRadius, mPaintActive); } /* * (non-Javadoc) * * @see * org.taptwo.android.widget.ViewFlow.ViewSwitchListener#onSwitched(android * .view.View, int) */ @Override public void onSwitched(View view, int position) { } /* * (non-Javadoc) * * @see * org.taptwo.android.widget.FlowIndicator#setViewFlow(org.taptwo.android * .widget.ViewFlow) */ @Override public void setViewFlow(ViewFlow view) { resetTimer(); viewFlow = view; flowWidth = viewFlow.getWidth(); invalidate(); } /* * (non-Javadoc) * * @see org.taptwo.android.widget.FlowIndicator#onScrolled(int, int, int, * int) */ @Override public void onScrolled(int h, int v, int oldh, int oldv) { setVisibility(View.VISIBLE); resetTimer(); flowWidth = viewFlow.getWidth(); if(viewFlow.getViewsCount()*flowWidth!=0){ currentScroll = h%(viewFlow.getViewsCount()*flowWidth); }else { currentScroll = h; } invalidate(); } /* * (non-Javadoc) * * @see android.view.View#onMeasure(int, int) */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec)); } /** * Determines the width of this view * * @param measureSpec * A measureSpec packed into an int * @return The width of the view, honoring constraints from measureSpec */ private int measureWidth(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); // We were told how big to be if (specMode == MeasureSpec.EXACTLY) { result = specSize; } // Calculate the width according the views count else { int count = 3; if (viewFlow != null) { count = viewFlow.getViewsCount(); } float temp = circleSeparation - 2*radius; result = (int) (getPaddingLeft() + getPaddingRight() + (count * 2 * radius) + (count - 1) * temp + 1); // Respect AT_MOST value if that was what is called for by // measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * Determines the height of this view * * @param measureSpec * A measureSpec packed into an int * @return The height of the view, honoring constraints from measureSpec */ private int measureHeight(int measureSpec) { int result = 0; int specMode = MeasureSpec.getMode(measureSpec); int specSize = MeasureSpec.getSize(measureSpec); // We were told how big to be if (specMode == MeasureSpec.EXACTLY) { result = specSize; } // Measure the height else { result = (int) (2 * radius + getPaddingTop() + getPaddingBottom() + 1); // Respect AT_MOST value if that was what is called for by // measureSpec if (specMode == MeasureSpec.AT_MOST) { result = Math.min(result, specSize); } } return result; } /** * Sets the fill color * * @param color * ARGB value for the text */ public void setFillColor(int color) { mPaintActive.setColor(color); invalidate(); } /** * Sets the stroke color * * @param color * ARGB value for the text */ public void setStrokeColor(int color) { mPaintInactive.setColor(color); invalidate(); } /** * Resets the fade out timer to 0. Creating a new one if needed */ private void resetTimer() { // Only set the timer if we have a timeout of at least 1 millisecond if (fadeOutTime > 0) { // Check if we need to create a new timer if (timer == null || timer._run == false) { // Create and start a new timer timer = new FadeTimer(); timer.execute(); } else { // Reset the current tiemr to 0 timer.resetTimer(); } } } /** * Counts from 0 to the fade out time and animates the view away when * reached */ private class FadeTimer extends AsyncTask<Void, Void, Void> { // The current count private int timer = 0; // If we are inside the timing loop private boolean _run = true; public void resetTimer() { timer = 0; } @Override protected Void doInBackground(Void... arg0) { while (_run) { try { // Wait for a millisecond Thread.sleep(1); // Increment the timer timer++; // Check if we've reached the fade out time if (timer == fadeOutTime) { // Stop running _run = false; } } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } return null; } @Override protected void onPostExecute(Void result) { animation = AnimationUtils.loadAnimation(getContext(), android.R.anim.fade_out); animation.setAnimationListener(animationListener); startAnimation(animation); } } @Override public void onAnimationEnd(Animation animation) { setVisibility(View.GONE); } @Override public void onAnimationRepeat(Animation animation) { } @Override public void onAnimationStart(Animation animation) { } }
2.2创建,FlowInicator工具类
package com.example.test.util; public interface FlowIndicator extends ViewFlow.ViewSwitchListener { /** * Set the current ViewFlow. This method is called by the ViewFlow when the * FlowIndicator is attached to it. * * @param view */ public void setViewFlow(ViewFlow view); /** * The scroll position has been changed. A FlowIndicator may implement this * method to reflect the current position * * @param h * @param v * @param oldh * @param oldv */ public void onScrolled(int h, int v, int oldh, int oldv); }
2.3创建ViewFlow工具类
/* * Copyright (C) 2011 Patrik Åkerfeldt * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.test.util; import android.content.Context; import android.content.res.Configuration; import android.content.res.TypedArray; import android.database.DataSetObserver; import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.AbsListView; import android.widget.Adapter; import android.widget.AdapterView; import android.widget.Scroller; import com.example.test.R; import java.util.ArrayList; import java.util.LinkedList; /** * * A horizontally scrollable {@link ViewGroup} with items populated from an * {@link Adapter}. The ViewFlow uses a buffer to store loaded {@link View}s in. * The default size of the buffer is 3 elements on both sides of the currently * visible {@link View}, making up a total buffer size of 3 * 2 + 1 = 7. The * buffer size can be changed using the {@code sidebuffer} xml attribute. * * @author http://blog.****.net/finddreams */ public class ViewFlow extends AdapterView<Adapter> { private static final int SNAP_VELOCITY = 1000; private static final int INVALID_SCREEN = -1; private final static int TOUCH_STATE_REST = 0; private final static int TOUCH_STATE_SCROLLING = 1; private LinkedList<View> mLoadedViews; private int mCurrentBufferIndex; private int mCurrentAdapterIndex; private int mSideBuffer = 2; private Scroller mScroller; private VelocityTracker mVelocityTracker; private int mTouchState = TOUCH_STATE_REST; private float mLastMotionX; private int mTouchSlop; private int mMaximumVelocity; private int mCurrentScreen; private int mNextScreen = INVALID_SCREEN; private boolean mFirstLayout = true; private ViewSwitchListener mViewSwitchListener; private Adapter mAdapter; private int mLastScrollDirection; private AdapterDataSetObserver mDataSetObserver; private FlowIndicator mIndicator; private int mLastOrientation = -1; private long timeSpan = 3000; private Handler handler; private OnGlobalLayoutListener orientationChangeListener = new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { getViewTreeObserver().removeGlobalOnLayoutListener( orientationChangeListener); setSelection(mCurrentAdapterIndex); } }; /** * Receives call backs when a new {@link View} has been scrolled to. */ public static interface ViewSwitchListener { /** * This method is called when a new View has been scrolled to. * * @param view * the {@link View} currently in focus. * @param position * The position in the adapter of the {@link View} currently in focus. */ void onSwitched(View view, int position); } public ViewFlow(Context context) { super(context); mSideBuffer = 3; init(); } public ViewFlow(Context context, int sideBuffer) { super(context); mSideBuffer = sideBuffer; init(); } public ViewFlow(Context context, AttributeSet attrs) { super(context, attrs); TypedArray styledAttrs = context.obtainStyledAttributes(attrs, R.styleable.ViewFlow); mSideBuffer = styledAttrs.getInt(R.styleable.ViewFlow_sidebuffer, 3); init(); } private void init() { mLoadedViews = new LinkedList<View>(); mScroller = new Scroller(getContext()); final ViewConfiguration configuration = ViewConfiguration .get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mMaximumVelocity = configuration.getScaledMaximumFlingVelocity(); } public void startAutoFlowTimer(){ handler = new Handler(){ @Override public void handleMessage(Message msg) { snapToScreen((mCurrentScreen+1)%getChildCount()); Message message = handler.obtainMessage(0); sendMessageDelayed(message, timeSpan); } }; Message message = handler.obtainMessage(0); handler.sendMessageDelayed(message, timeSpan); } public void stopAutoFlowTimer(){ if(handler!=null) handler.removeMessages(0); handler = null; } public void onConfigurationChanged(Configuration newConfig) { if (newConfig.orientation != mLastOrientation) { mLastOrientation = newConfig.orientation; getViewTreeObserver().addOnGlobalLayoutListener(orientationChangeListener); } } public int getViewsCount() { return mSideBuffer; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); final int width = MeasureSpec.getSize(widthMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); if (widthMode != MeasureSpec.EXACTLY && !isInEditMode()) { throw new IllegalStateException( "ViewFlow can only be used in EXACTLY mode."); } final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode != MeasureSpec.EXACTLY && !isInEditMode()) { throw new IllegalStateException( "ViewFlow 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) { mScroller.startScroll(0, 0, mCurrentScreen * width, 0, 0); mFirstLayout = false; } } @Override protected void onLayout(boolean changed, int l, int t, int r, 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(MotionEvent ev) { if (getChildCount() == 0) return false; 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; mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; if(handler!=null) handler.removeMessages(0); 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_SCROLLING; } if (mTouchState == TOUCH_STATE_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); } } return true; } break; case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_SCROLLING) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int velocityX = (int) velocityTracker.getXVelocity(); if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // Fling hard enough to move left snapToScreen(mCurrentScreen - 1); } else if (velocityX < -SNAP_VELOCITY && 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; if(handler!=null){ Message message = handler.obtainMessage(0); handler.sendMessageDelayed(message, timeSpan); } break; case MotionEvent.ACTION_CANCEL: mTouchState = TOUCH_STATE_REST; } return false; } @Override public boolean onTouchEvent(MotionEvent ev) { if (getChildCount() == 0) return false; 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; mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; if(handler!=null) handler.removeMessages(0); 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_SCROLLING; } if (mTouchState == TOUCH_STATE_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); } } return true; } break; case MotionEvent.ACTION_UP: if (mTouchState == TOUCH_STATE_SCROLLING) { final VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int velocityX = (int) velocityTracker.getXVelocity(); if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) { // Fling hard enough to move left snapToScreen(mCurrentScreen - 1); } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < getChildCount() - 1) { // Fling hard enough to move right snapToScreen(mCurrentScreen + 1); } // else if (velocityX < -SNAP_VELOCITY // && mCurrentScreen == getChildCount() - 1) { // snapToScreen(0); // } // else if (velocityX > SNAP_VELOCITY // && mCurrentScreen == 0) { // snapToScreen(getChildCount() - 1); // } else { snapToDestination(); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } } mTouchState = TOUCH_STATE_REST; if(handler!=null){ Message message = handler.obtainMessage(0); handler.sendMessageDelayed(message, timeSpan); } break; case MotionEvent.ACTION_CANCEL: snapToDestination(); mTouchState = TOUCH_STATE_REST; } return true; } @Override protected void onScrollChanged(int h, int v, int oldh, int oldv) { super.onScrollChanged(h, v, oldh, oldv); if (mIndicator != null) { /* * The actual horizontal scroll origin does typically not match the * perceived one. Therefore, we need to calculate the perceived * horizontal scroll origin here, since we use a view buffer. */ int hPerceived = h + (mCurrentAdapterIndex - mCurrentBufferIndex) * getWidth(); mIndicator.onScrolled(hPerceived, v, oldh, oldv); } } private void snapToDestination() { final int screenWidth = getWidth(); final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth; snapToScreen(whichScreen); } private void snapToScreen(int whichScreen) { mLastScrollDirection = whichScreen - mCurrentScreen; if (!mScroller.isFinished()) return; whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); mNextScreen = whichScreen; final int newX = whichScreen * getWidth(); final int delta = newX - getScrollX(); mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2); invalidate(); } @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)); mNextScreen = INVALID_SCREEN; postViewSwitched(mLastScrollDirection); } } /** * Scroll to the {@link View} in the view buffer specified by the index. * * @param indexInBuffer * Index of the view in the view buffer. */ private void setVisibleView(int indexInBuffer, boolean uiThread) { mCurrentScreen = Math.max(0, Math.min(indexInBuffer, getChildCount() - 1)); int dx = (mCurrentScreen * getWidth()) - mScroller.getCurrX(); mScroller.startScroll(mScroller.getCurrX(), mScroller.getCurrY(), dx, 0, 0); if(dx == 0) onScrollChanged(mScroller.getCurrX() + dx, mScroller.getCurrY(), mScroller.getCurrX() + dx, mScroller.getCurrY()); if (uiThread) invalidate(); else postInvalidate(); } /** * Set the listener that will receive notifications every time the {code * ViewFlow} scrolls. * * @param l * the scroll listener */ public void setOnViewSwitchListener(ViewSwitchListener l) { mViewSwitchListener = l; } @Override public Adapter getAdapter() { return mAdapter; } @Override public void setAdapter(Adapter adapter) { setAdapter(adapter, 0); } public void setAdapter(Adapter adapter, int initialPosition) { if (mAdapter != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); } mAdapter = adapter; if (mAdapter != null) { mDataSetObserver = new AdapterDataSetObserver(); mAdapter.registerDataSetObserver(mDataSetObserver); } if (mAdapter == null || mAdapter.getCount() == 0) return; setSelection(initialPosition); } @Override public View getSelectedView() { return (mCurrentBufferIndex < mLoadedViews.size() ? mLoadedViews .get(mCurrentBufferIndex) : null); } @Override public int getSelectedItemPosition() { return mCurrentAdapterIndex; } /** * Set the FlowIndicator * * @param flowIndicator */ public void setFlowIndicator(FlowIndicator flowIndicator,int size) { if(size==1){ return; }else{ mIndicator = flowIndicator; mIndicator.setViewFlow(this); } } @Override public void setSelection(int position) { mNextScreen = INVALID_SCREEN; mScroller.forceFinished(true); if (mAdapter == null) return; position = Math.max(position, 0); position = Math.min(position, mAdapter.getCount()-1); ArrayList<View> recycleViews = new ArrayList<View>(); View recycleView; while (!mLoadedViews.isEmpty()) { recycleViews.add(recycleView = mLoadedViews.remove()); detachViewFromParent(recycleView); } View currentView = makeAndAddView(position, true, (recycleViews.isEmpty() ? null : recycleViews.remove(0))); mLoadedViews.addLast(currentView); for(int offset = 1; mSideBuffer - offset >= 0; offset++) { int leftIndex = position - offset; int rightIndex = position + offset; if(leftIndex >= 0) mLoadedViews.addFirst(makeAndAddView(leftIndex, false, (recycleViews.isEmpty() ? null : recycleViews.remove(0)))); if(rightIndex < mAdapter.getCount()) mLoadedViews.addLast(makeAndAddView(rightIndex, true, (recycleViews.isEmpty() ? null : recycleViews.remove(0)))); } mCurrentBufferIndex = mLoadedViews.indexOf(currentView); mCurrentAdapterIndex = position; for (View view : recycleViews) { removeDetachedView(view, false); } requestLayout(); setVisibleView(mCurrentBufferIndex, false); if (mIndicator != null) { mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex), mCurrentAdapterIndex); } if (mViewSwitchListener != null) { mViewSwitchListener .onSwitched(mLoadedViews.get(mCurrentBufferIndex), mCurrentAdapterIndex); } } private void resetFocus() { mLoadedViews.clear(); removeAllViewsInLayout(); for (int i = Math.max(0, mCurrentAdapterIndex - mSideBuffer); i < Math .min(mAdapter.getCount(), mCurrentAdapterIndex + mSideBuffer + 1); i++) { mLoadedViews.addLast(makeAndAddView(i, true, null)); if (i == mCurrentAdapterIndex) mCurrentBufferIndex = mLoadedViews.size() - 1; } requestLayout(); } private void postViewSwitched(int direction) { if (direction == 0) return; if (direction > 0) { // to the right mCurrentAdapterIndex++; mCurrentBufferIndex++; // if(direction > 1) { // mCurrentAdapterIndex += mAdapter.getCount() - 2; // mCurrentBufferIndex += mAdapter.getCount() - 2; // } View recycleView = null; // Remove view outside buffer range if (mCurrentAdapterIndex > mSideBuffer) { recycleView = mLoadedViews.removeFirst(); detachViewFromParent(recycleView); // removeView(recycleView); mCurrentBufferIndex--; } // Add new view to buffer int newBufferIndex = mCurrentAdapterIndex + mSideBuffer; if (newBufferIndex < mAdapter.getCount()) mLoadedViews.addLast(makeAndAddView(newBufferIndex, true, recycleView)); } else { // to the left mCurrentAdapterIndex--; mCurrentBufferIndex--; // if(direction < -1) { // mCurrentAdapterIndex -= mAdapter.getCount() - 2; // mCurrentBufferIndex -= mAdapter.getCount() - 2; // } View recycleView = null; // Remove view outside buffer range if (mAdapter.getCount() - 1 - mCurrentAdapterIndex > mSideBuffer) { recycleView = mLoadedViews.removeLast(); detachViewFromParent(recycleView); } // Add new view to buffer int newBufferIndex = mCurrentAdapterIndex - mSideBuffer; if (newBufferIndex > -1) { mLoadedViews.addFirst(makeAndAddView(newBufferIndex, false, recycleView)); mCurrentBufferIndex++; } } requestLayout(); setVisibleView(mCurrentBufferIndex, true); if (mIndicator != null) { mIndicator.onSwitched(mLoadedViews.get(mCurrentBufferIndex), mCurrentAdapterIndex); } if (mViewSwitchListener != null) { mViewSwitchListener .onSwitched(mLoadedViews.get(mCurrentBufferIndex), mCurrentAdapterIndex); } } private View setupChild(View child, boolean addToEnd, boolean recycle) { LayoutParams p = (LayoutParams) child .getLayoutParams(); if (p == null) { p = new AbsListView.LayoutParams( LayoutParams.FILL_PARENT, LayoutParams.WRAP_CONTENT, 0); } if (recycle) attachViewToParent(child, (addToEnd ? -1 : 0), p); else addViewInLayout(child, (addToEnd ? -1 : 0), p, true); return child; } private View makeAndAddView(int position, boolean addToEnd, View convertView) { View view = mAdapter.getView(position, convertView, this); return setupChild(view, addToEnd, convertView != null); } class AdapterDataSetObserver extends DataSetObserver { @Override public void onChanged() { View v = getChildAt(mCurrentBufferIndex); if (v != null) { for (int index = 0; index < mAdapter.getCount(); index++) { if (v.equals(mAdapter.getItem(index))) { mCurrentAdapterIndex = index; break; } } } resetFocus(); } @Override public void onInvalidated() { // Not yet implemented! } } public void setTimeSpan(long timeSpan) { this.timeSpan = timeSpan; } public void setmSideBuffer(int mSideBuffer) { this.mSideBuffer = mSideBuffer; } }
2.4创建ProgressWebView工具类(点击广告要跳转的webview)
package com.example.test.util; import android.content.Context; import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.webkit.WebView; import android.widget.ProgressBar; import com.example.test.R; /** * @Description: 带进度条的WebView * @author http://blog.****.net/finddreams */ @SuppressWarnings("deprecation") public class ProgressWebView extends WebView { private ProgressBar progressbar; public ProgressWebView(Context context, AttributeSet attrs) { super(context, attrs); progressbar = new ProgressBar(context, null, android.R.attr.progressBarStyleHorizontal); progressbar.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT, 10, 0, 0)); Drawable drawable = context.getResources().getDrawable(R.drawable.progress_bar_states); progressbar.setProgressDrawable(drawable); addView(progressbar); // setWebViewClient(new WebViewClient(){}); setWebChromeClient(new WebChromeClient()); //是否支持缩放 getSettings().setSupportZoom(true); getSettings().setBuiltInZoomControls(true); } public class WebChromeClient extends android.webkit.WebChromeClient { @Override public void onProgressChanged(WebView view, int newProgress) { if (newProgress == 100) { progressbar.setVisibility(GONE); } else { if (progressbar.getVisibility() == GONE) progressbar.setVisibility(VISIBLE); progressbar.setProgress(newProgress); } super.onProgressChanged(view, newProgress); } } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { LayoutParams lp = (LayoutParams) progressbar.getLayoutParams(); lp.x = l; lp.y = t; progressbar.setLayoutParams(lp); super.onScrollChanged(l, t, oldl, oldt); } }
3.创建BaseWebActivity(及得在配置文件注册activity)
package com.example.test.activity; import android.app.Activity; import android.content.Intent; import android.os.Build; import android.os.Bundle; import android.view.KeyEvent; import android.view.Window; import android.view.WindowManager; import android.webkit.WebSettings; import android.webkit.WebView; import android.webkit.WebViewClient; import com.example.test.R; import com.example.test.base.BaseApplication; import com.example.test.util.ProgressWebView; /** * @Description:WebView界面,带自定义进度条显示 * @author http://blog.****.net/finddreams */ public class BaseWebActivity extends Activity { private static String TAG = BaseWebActivity.class.getSimpleName() + "==="; protected ProgressWebView mWebView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_baseweb); BaseApplication.getApp().addActivity(this); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { Window window = getWindow(); // 有些情况下需要先清除透明flag window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS); window.setStatusBarColor(getResources().getColor(R.color.colorPrimaryDark)); } mWebView = (ProgressWebView) findViewById(R.id.baseweb_webview); mWebView.getSettings().setJavaScriptEnabled(true); initData(); } protected void initData() { Intent intent = getIntent(); Bundle bundle = intent.getExtras(); String urls = bundle.getString("url"); mWebView.loadUrl(urls); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.getSettings().setAppCacheEnabled(true); //设置 缓存模式 mWebView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); // 开启 DOM storage API 功能 mWebView.getSettings().setDomStorageEnabled(true); mWebView.setWebViewClient(new WebViewClient(){ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { // view.loadUrl(url); return super.shouldOverrideUrlLoading(view, url); } }); } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { try{ if (keyCode == KeyEvent.KEYCODE_BACK && mWebView.canGoBack()) { mWebView.goBack();// 返回前一个页面 return true; }else{ BaseApplication.getApp().finishActivity(this); finish(); } }catch (Exception e){ } return super.onKeyDown(keyCode, event); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); mWebView = null; BaseApplication.getApp().finishActivity(this); } }
3.drawable相关文件
3.1advertising_bg.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android"> <corners android:radius="5dp"></corners><!--设置圆角--> </shape>
3.2progress_bar_states.xml
<?xml version="1.0" encoding="utf-8"?> <!-- 层叠 --> <layer-list xmlns:android="http://schemas.android.com/apk/res/android" > <item android:id="@android:id/background"> <shape> <corners android:radius="2dp" /> <gradient android:angle="270" android:centerColor="#E3E3E3" android:endColor="#E6E6E6" android:startColor="#C8C8C8" /> </shape> </item> <item android:id="@android:id/progress"> <clip> <shape> <corners android:radius="2dp" /> <gradient android:centerColor="#4AEA2F" android:endColor="#31CE15" android:startColor="#5FEC46" /> </shape> </clip> </item> </layer-list>
4.图片适配器ImagePagerAdapter
/* * Copyright 2014 trinea.cn All right reserved. This software is the confidential and proprietary information of * trinea.cn ("Confidential Information"). You shall not disclose such Confidential Information and shall use it only in * accordance with the terms of the license agreement you entered into with trinea.cn. */ package com.example.test.adapter; import android.app.Dialog; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.example.test.R; import com.example.test.activity.BaseWebActivity; import java.util.List; /** * @author http://blog.****.net/finddreams * @Description: 图片适配器 */ public class ImagePagerAdapter extends BaseAdapter { private List<String> imageIdList; private List<String> linkUrlArray; private int size; private boolean isInfiniteLoop; private Dialog dialogs; public ImagePagerAdapter(Context context, List<String> imageIdList,List<String> urllist, Dialog dialogs) { this.imageIdList = imageIdList; if (imageIdList != null) { this.size = imageIdList.size(); } this.linkUrlArray = urllist; isInfiniteLoop = false; this.dialogs = dialogs; } @Override public int getCount() { // Infinite loop return isInfiniteLoop ? Integer.MAX_VALUE : imageIdList.size(); } /** * get really position * * @param position * @return */ private int getPosition(int position) { return isInfiniteLoop ? position % size : position; } @Override public View getView(final int position, View view, ViewGroup container) { final ViewHolder holder; if (view == null) { holder = new ViewHolder(); view = holder.imageView = new ImageView(container.getContext()); holder.imageView .setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT , ViewGroup.LayoutParams.MATCH_PARENT)); holder.imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); holder.imageView.setBackgroundResource(R.drawable.advertising_bg); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); } //TODO:view的布局需要添加容器,glide对需要imageview不被设置tag Context context = holder.imageView.getContext(); Glide.with(context) .load(this.imageIdList.get(getPosition(position))) .error(R.mipmap.loaderror).placeholder(R.mipmap.loaderror). fallback(R.mipmap.loaderror).into(holder.imageView); // Glide.with(context) // .load(this.imageIdList.get(getPosition(position))).fitCenter().into(holder.imageView); // imageLoader.displayImage( // (String) this.imageIdList.get(getPosition(position)), // holder.imageView, options); holder.imageView.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { String url = linkUrlArray.get(ImagePagerAdapter.this .getPosition(position)); Bundle bundle = new Bundle(); bundle.putString("url", url); Intent intent = new Intent(arg0.getContext(), BaseWebActivity.class); intent.putExtras(bundle); arg0.getContext().startActivity(intent); dialogs.dismiss(); } }); return view; } private static class ViewHolder { ImageView imageView; } /** * @return the isInfiniteLoop */ public boolean isInfiniteLoop() { return isInfiniteLoop; } /** * @param isInfiniteLoop the isInfiniteLoop to set */ public ImagePagerAdapter setInfiniteLoop(boolean isInfiniteLoop) { this.isInfiniteLoop = isInfiniteLoop; return this; } @Override public Object getItem(int arg0) { // TODO Auto-generated method stub return arg0; } @Override public long getItemId(int arg0) { // TODO Auto-generated method stub return arg0; } }
5.相关layout文件
5.1activity_main_advertising.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <RelativeLayout android:id="@+id/rl_allguangao" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true"> <FrameLayout android:id="@+id/framelayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <com.example.test.util.ViewFlow android:id="@+id/viewflow" android:layout_width="@dimen/px626" android:layout_height="@dimen/px800" /> <com.example.test.util.CircleFlowIndicator android:id="@+id/viewflowindic" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center_horizontal|bottom" android:layout_marginBottom="@dimen/px20" android:layout_marginLeft="@dimen/px20" android:layout_marginRight="@dimen/px20" android:padding="2dip" app:activeColor="#ffffff" app:activeType="fill" app:circleSeparation="20dip" app:inactiveColor="#999999" app:inactiveType="fill" app:radius="4dip" /> </FrameLayout> <ImageView android:id="@+id/iv_close" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@id/framelayout" android:layout_centerHorizontal="true" android:layout_marginTop="@dimen/px20" android:scaleType="centerCrop" android:src="@mipmap/advclose" /> </RelativeLayout> </RelativeLayout>
5.2activity_baseweb.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <com.example.test.util.ProgressWebView android:id="@+id/baseweb_webview" android:layout_width="fill_parent" android:layout_height="fill_parent" android:fadeScrollbars="true" android:scrollbarStyle="insideOverlay" /> </LinearLayout>
6.value相关文件
6.1arrt.xml
<attr name="rightPadding" format="dimension" /> <declare-styleable name="CircleImageView"> <attr name="border_width" format="dimension" /> <attr name="border_color" format="color" /> </declare-styleable> <declare-styleable name="ViewFlow"> <attr name="sidebuffer" format="integer" /> </declare-styleable> <declare-styleable name="CircleFlowIndicator"> <attr name="activeColor" format="color" /> <attr name="inactiveColor" format="color" /> <attr name="radius" format="dimension" /> <attr name="centered" format="boolean" /> <attr name="fadeOut" format="integer" /> <attr name="inactiveType"> <flag name="stroke" value="0" /> <flag name="fill" value="1" /> </attr> <attr name="activeType"> <flag name="stroke" value="0" /> <flag name="fill" value="1" /> </attr> <attr name="circleSeparation" format="dimension" /> <attr name="activeRadius" format="dimension" /> </declare-styleable>
6.2dimens.xml
<resources> <dimen name="px20">8dp</dimen> <dimen name="px626">300dp</dimen> <dimen name="px800">400dp</dimen> </resources>
6.3ids.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <item type="id" name="tag_glide" /> </resources>
6.4设置完ids文件后再application的oncreate方法中添加下面代码
ViewTarget.setTagId(R.id.tag_glide);
7.主页Activity
/** * 广告相关 */ private ViewFlow mViewFlow; private CircleFlowIndicator mFlowIndicator; private ArrayList<String> imageUrlList = new ArrayList<String>(); private ArrayList<String> linkUrlArray = new ArrayList<String>(); private LayoutInflater inflater; private RelativeLayout layout; private ImageView iv_close; private Dialog dialogs;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); BaseApplication.getApp().addActivity(this); initView(); initData(); }
/** * 初始化控件 */ private void initView() {
/** * 广告相关 */ inflater = LayoutInflater.from(MainActivity.this); layout = (RelativeLayout) inflater.inflate(R.layout.activity_main_advertising, null); iv_close = (ImageView) layout.findViewById(R.id.iv_close); mViewFlow = (ViewFlow) layout.findViewById(R.id.viewflow); mViewFlow.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { dialogs.dismiss(); } }); mFlowIndicator = (CircleFlowIndicator) layout.findViewById(R.id.viewflowindic); iv_close.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dialogs.dismiss(); } });
/** * 初始化数据 */ private void initData() {
//广告相关 linkUrlArray.add("http://www.baidu.com"); linkUrlArray.add("https://www.****.net/"); linkUrlArray.add("https://www.oschina.net/"); imageUrlList.add("http://cn.bing.com/az/hprichbg/rb/Dongdaemun_ZH-CN10736487148_1920x1080.jpg"); imageUrlList.add("http://pic.people.com.cn/NMediaFile/2019/0610/MAIN201906101623000225736784754.jpg"); imageUrlList.add("http://www.gregscott.com/gjs_2007_spring/hummingbird/20070311_1948_100_0560.rufous_humminbird.jpg"); initBanner(imageUrlList);
}
private void showDialog() { dialogs.setCanceledOnTouchOutside(false);//dialog弹出后会点击屏幕,dialog不消失;点击物理返回键dialog消失 dialogs.show(); dialogs.getWindow().setContentView(layout); dialogs.getWindow().setBackgroundDrawableResource(R.color.transparent); } /** * @param imageUrlList 广告图片url list */ private void initBanner(ArrayList<String> imageUrlList) { dialogs = new AlertDialog.Builder(MainActivity.this).create(); mViewFlow.setAdapter(new ImagePagerAdapter(this, imageUrlList, linkUrlArray, dialogs).setInfiniteLoop(true)); mViewFlow.setmSideBuffer(imageUrlList.size()); // 实际图片张数, mViewFlow.setFlowIndicator(mFlowIndicator, imageUrlList.size()); mViewFlow.setTimeSpan(3500); mViewFlow.setSelection(imageUrlList.size() * 1000); // 设置初始位置 if (imageUrlList.size() > 1) {//大于1页广告开启轮播 mViewFlow.startAutoFlowTimer(); // 启动自动播放 } else { mFlowIndicator.setVisibility(View.GONE); } showDialog(); }
}