<android>自定义banner 带标题及扁圆Indicator 轮播效果 及手势等处理

                       自定义banner 带标题及扁圆Indicator 轮播效果 及手势等处理 


先上图:

                                                     

 

分析:这里我们用viewpager来实现,圆角效果用cardview来包裹,小圆点用画笔绘制,加上动画就搞定。

第一步:

重写viewpager(AutoScrollViewPager类):

public class AutoScrollViewPager extends ViewPager {
    private static final String TAG = "AutoScrollViewPager";
    private AutoScrollHandler autoScrollHandler;
    private Context mContext;
    private int change_anmin;
    private int change_duration;
    int speed = 500; //默认移动速度
    private int indexCount;
    private float mXp;
    private float mYp;
    FixedSpeedScroller mScroller = null;

    public AutoScrollViewPager(@NonNull Context context) {
        this(context, null);
        mContext = context;
    }

    public AutoScrollViewPager(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        mContext = context;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BannerIndicator);
        change_anmin = array.getInteger(R.styleable.AutoScrollViewPager_change_anmin, 1);
        change_duration = array.getInteger(R.styleable.AutoScrollViewPager_change_duration, 5000);
        autoScrollHandler = new AutoScrollHandler(this, change_duration);
        controlViewPagerSpeed();
        setPageMargin(20);
    }

    public AutoScrollViewPager(@NonNull Context context, @Nullable AttributeSet attrs, Context mContext) {
        super(context, attrs);
        this.mContext = mContext;
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BannerIndicator);
        change_anmin = array.getInteger(R.styleable.AutoScrollViewPager_change_anmin, 1);
        change_duration = array.getInteger(R.styleable.AutoScrollViewPager_change_duration, 5);
        autoScrollHandler = new AutoScrollHandler(this, change_duration);
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {

        /**
         * 根据getAdapter获取外部传递的size是多少,如果为1则不允许移动 只允许点击
         * 否则允许滑动和点击切按住时通知轮播,放开时启动轮播
         */
        if (indexCount == 1) {
            switch (ev.getAction()) {
                case MotionEvent.ACTION_DOWN:
                    mXp = ev.getX();
                    mYp = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    return false;

                case MotionEvent.ACTION_UP:
                    return super.dispatchTouchEvent(ev);
            }
            return super.dispatchTouchEvent(ev);

        } else {
            int action = ev.getAction();
            if (action == ACTION_UP || action == ACTION_CANCEL || action == ACTION_OUTSIDE) {
                startAutoPlay();
            } else if (action == ACTION_DOWN) {
                stopAutoPlay();
            }
            return super.dispatchTouchEvent(ev);
        }
    }

    /**
     * 开启轮播 同时获取count
     */
    public void startAutoPlay() {
        if (autoScrollHandler != null) {
            stopAutoPlay();
            autoScrollHandler.start();
        }

        ViewPagerAdapter adapter = (ViewPagerAdapter) getAdapter();
        assert adapter != null;
        indexCount = adapter.ssss();
    }

    /**
     * 停止轮播 同时获取count
     */
    public void stopAutoPlay() {
        if (autoScrollHandler != null) {
            autoScrollHandler.stop();
            autoScrollHandler.removeCallbacksAndMessages(null);
        }
        ViewPagerAdapter adapter = (ViewPagerAdapter) getAdapter();
        assert adapter != null;
        indexCount = adapter.ssss();
    }

    // 传递速度值
    public void setSpeed(int speed) {
        this.speed = speed;
    }


    /**
     * 修改vp移动速度
     */
    private void controlViewPagerSpeed() {
        try {
            Field mField;
            mField = ViewPager.class.getDeclaredField("mScroller");
            mField.setAccessible(true);
            mScroller = new FixedSpeedScroller(mContext, new AccelerateInterpolator());
            mScroller.setmDuration(speed); // 2000ms
            mField.set(this, mScroller);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

改变vp移动速度继承scroller的重写:

public class FixedSpeedScroller extends Scroller {
    private int mDuration = 1000;

    public FixedSpeedScroller(Context context) {
        super(context);
        // TODO Auto-generated constructor stub
    }

    public FixedSpeedScroller(Context context, Interpolator interpolator) {
        super(context, interpolator);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy, int duration) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    @Override
    public void startScroll(int startX, int startY, int dx, int dy) {
        // Ignore received duration, use fixed one instead
        super.startScroll(startX, startY, dx, dy, mDuration);
    }

    public void setmDuration(int time) {
        mDuration = time;
    }

    public int getmDuration() {
        return mDuration;
    }
}

第二步 构建Handler定时器(AutoScrollHandler类):

public class AutoScrollHandler extends Handler {
    private static final String TAG = "AutoScrollHandler";
    private WeakReference<AutoScrollViewPager> mBannerRef;
    private static final int MSG_CHANGE_SELECTION = 1;
    private static int AUTO_SCROLL_TIME = 0;

    public AutoScrollHandler(AutoScrollViewPager autoScrollViewPager, int change_duration) {
        mBannerRef = new WeakReference<>(autoScrollViewPager);
        AUTO_SCROLL_TIME = change_duration;
    }


    public void start() {
        removeMessages(MSG_CHANGE_SELECTION);
        sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
    }

    public void stop() {
        removeMessages(MSG_CHANGE_SELECTION);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == MSG_CHANGE_SELECTION) {
            if (mBannerRef == null || mBannerRef.get() == null) {
                return;
            }
            AutoScrollViewPager banner = mBannerRef.get();
            int current = banner.getCurrentItem();
/*            if (current == banner.getAdapter().getCount() - 1)
                current = -1;*/
            banner.setCurrentItem(current + 1);
            sendEmptyMessageDelayed(MSG_CHANGE_SELECTION, AUTO_SCROLL_TIME);
        }
    }

}

第三步:绘制indicator(BannerItemView类)

ublic class BannerItemView extends View {
    private static final String TAG = "BannerItemView";
    private Paint mPaint;
    private float rectWidth;
    private RectF rectF;
    public static final int CENTER = 0;
    public static final int LEFT = 1;
    public static final int RIGHT = 2;
    private int loaction = CENTER;

    public BannerItemView(Context context) {
        this(context, null);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectF = new RectF();
        mPaint.setColor(Color.RED);
    }

    public BannerItemView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectF = new RectF();
        mPaint.setColor(Color.RED);
    }

    public BannerItemView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectF = new RectF();
        mPaint.setColor(Color.RED);
    }

    public BannerItemView(Context context, int loaction) {
        this(context);
        this.loaction = loaction;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        switch (loaction) {
            case CENTER:
                rectF.left = getWidth() / 2 - getHeight() / 2 - rectWidth;
                rectF.right = getHeight() / 2 + getWidth() / 2 + rectWidth;
                rectF.top = 0;
                rectF.bottom = getHeight();
                break;
            case LEFT:
                rectF.left = getWidth() - getHeight() - rectWidth;
                rectF.right = getWidth();
                rectF.top = 0;
                rectF.bottom = getHeight();
                break;
            case RIGHT:
                rectF.left = 0;
                rectF.right = getHeight() - rectWidth;
                rectF.top = 0;
                rectF.bottom = getHeight();
                break;
        }
        canvas.drawRoundRect(rectF, getHeight() / 2, getHeight() / 2, mPaint);
    }

    public float getRectWidth() {
        return rectWidth;
    }


    public void setColor(int color) {

        mPaint.setColor(color);
    }

    public void setRectWidth(float rectWidth) {
        this.rectWidth = rectWidth;

        invalidate();
    }

    public int getLoaction() {
        return loaction;
    }

    public void setLoaction(int loaction) {
        this.loaction = loaction;
    }
}

第四步:将绘制的Indicator加入布局(BannerIndicator类)

public class BannerIndicator extends LinearLayout {
    private static final String TAG = "BannerIndicator";

    private int dashGap;
    private int position;
    private ViewPager viewPager;
    private int slider_width;
    private int slider_height;
    private int sliderAlign;
    private int current_color;
    private int pasted_color;
    private int change_speech = 200;
    private List<GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean> drawableList;

    public BannerIndicator(Context context) {
        this(context, null);
    }

    public BannerIndicator(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BannerIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        setOrientation(HORIZONTAL);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.BannerIndicator);
        dashGap = (int) array.getDimension(R.styleable.BannerIndicator_gap, 3);
        slider_width = (int) array.getDimension(R.styleable.BannerIndicator_slider_width, 12);
        slider_height = (int) array.getDimension(R.styleable.BannerIndicator_slider_height, 4);
        sliderAlign = array.getInt(R.styleable.BannerIndicator_slider_align, 1);

        current_color = array.getColor(R.styleable.BannerIndicator_current_color, Color.RED); //当前颜色
        pasted_color = array.getColor(R.styleable.BannerIndicator_pasted_color, Color.BLACK); //过去亚颜色
        change_speech = array.getInt(R.styleable.BannerIndicator_change_speech, 200); //动画时间

        array.recycle();
    }


    public void setUpWidthViewPager(final ViewPager viewPager, final List<GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean> drawableList1) {

        drawableList = new ArrayList<>();
        if (this.drawableList != null && drawableList.size() != 0)
            this.drawableList.clear();
        this.drawableList.addAll(drawableList1);

        removeAllViews();
        if (viewPager == null || viewPager.getAdapter() == null)
            return;
        position = 0;
        this.viewPager = viewPager;
        for (int i = 0; i < drawableList.size(); i++) {
            BannerItemView imageView = new BannerItemView(getContext(), sliderAlign);
            LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(slider_width, slider_height);
            if (i > 0) {
                layoutParams.setMargins(dashGap, 0, 0, 0);
                imageView.setAlpha(0.4f);
            } else {
                layoutParams.setMargins(0, 0, 0, 0);
                imageView.setAlpha(1);
            }
            imageView.setLayoutParams(layoutParams);
            addView(imageView);
            setLarge(0);
        }
        viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {

                try {
                    if (BannerIndicator.this.position != position % drawableList.size()) {
                        resetSize(BannerIndicator.this.position, position % drawableList.size());
                        BannerIndicator.this.position = position % drawableList.size();
                    }
                } catch (Exception e) {

                }

            }
        });
    }

    private void resetSize(int position, int current) {
        setLarge(current);
        setSmall(position);
    }


    //指示器增大同时设置透明度变化
    private void setLarge(int position) {
        if (getChildAt(position) instanceof BannerItemView) {
            AnimatorSet set = new AnimatorSet();
            ValueAnimator animator = getEnlarge((BannerItemView) getChildAt(position));
            ValueAnimator alpha = ObjectAnimator.ofFloat(getChildAt(position), "alpha", 1f, 1f);
            set.play(animator).with(alpha);
            set.setDuration(change_speech);
            set.start();

            try {
                for (int i = 0; i < drawableList.size(); i++) {
                    if (position == i) {
                        BannerItemView childAt = (BannerItemView) getChildAt(i);
                        childAt.setColor(current_color);
                    } else {
                        BannerItemView childAt = (BannerItemView) getChildAt(i);
                        childAt.setColor(pasted_color);
                    }
                }

            } catch (Exception e) {

            }

        }
    }


    //放大动画
    private ValueAnimator getEnlarge(BannerItemView roundRectView) {
        return ObjectAnimator.ofFloat(roundRectView,
                "rectWidth",
                0, getOffset(roundRectView));
    }

    //根据大小变化方向获取指示器大小偏移量
    private int getOffset(BannerItemView bannerItemView) {
        int offsest = 0;
        switch (bannerItemView.getLoaction()) {
            case BannerItemView.CENTER:
                offsest = (slider_width - slider_height) / 2;
                break;
            case BannerItemView.LEFT:
                offsest = slider_width - slider_height;
                break;
            case BannerItemView.RIGHT:
                offsest = slider_width - slider_height;
                break;
        }
        return offsest;
    }

    //缩小动画
    private ValueAnimator getShrink(BannerItemView roundRectView) {
        return ObjectAnimator.ofFloat(roundRectView,
                "rectWidth",
                getOffset(roundRectView), 0);
    }

    //缩小动画同事伴随透明度变化
    public void setSmall(int small) {
        if (getChildAt(small) instanceof BannerItemView) {
            AnimatorSet set = new AnimatorSet();
            ValueAnimator alpha = ObjectAnimator.ofFloat(getChildAt(position), "alpha", 1, 0.4f);
            ValueAnimator animator = getShrink((BannerItemView) getChildAt(small));
            set.play(animator).with(alpha);
            set.setDuration(618);
            set.start();
        }
    }
}

 

第五步: viewpager的适配器(ViewPagerAdapter类)

public class ViewPagerAdapter extends PagerAdapter {
    private Context mContext;
    private List<View> mCache;
    List<View> views = new ArrayList<>();
    private List<GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean> drawableList;
    private final RequestOptions optionss;

    public ViewPagerAdapter(List<GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean> list, Context context) {
        drawableList = new ArrayList<>();
        optionss = new RequestOptions();
        optionss.placeholder(R.mipmap.pre_img);//图片加载出来前,显示的图片
        optionss.fallback(R.mipmap.pre_img); //url为空的时候,显示的图片
        optionss.error(R.mipmap.pre_img);//图片加载失败后,显示的图片

        if (drawableList.size() != 0)
            drawableList.clear();

        drawableList.addAll(list);
        mContext = context;
        mCache = new ArrayList<>();
        for (int i = 0; i < drawableList.size(); i++) {
            ImageView imageView = new ImageView(mContext);
            Glide.with(mContext).load(drawableList.get(i).getPic()).apply(optionss).into(imageView);
            imageView.setScaleType(ImageView.ScaleType.FIT_XY);
            views.add(imageView);
        }
    }

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

    @Override
    public int getCount() {
        return Integer.MAX_VALUE;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, final int position) {
        if (drawableList != null && drawableList.size() > 0) {
            View imageView = null;
            if (mCache.isEmpty()) {
                imageView = View.inflate(container.getContext(), R.layout.item_imagess, null);
            } else {
                imageView = mCache.remove(0);
            }
            ImageView xxximg_ = (ImageView) imageView.findViewById(R.id.xxximg_);
            TextView show_tv_show = (TextView) imageView.findViewById(R.id.show_tv_show);
            Glide.with(mContext).load(drawableList.get(position % drawableList.size()).getPic()).into(xxximg_);
            show_tv_show.setText(drawableList.get(position % drawableList.size()).getB_name() + "");
            xxximg_.setScaleType(ImageView.ScaleType.FIT_XY);
            container.addView(imageView);
            final View finalImageView = imageView;
            imageView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    try {

                        bannerListener.ItemClick(position % drawableList.size(), drawableList.get(position % drawableList.size()));

                    } catch (Exception e) {

                    }
                }
            });
            return imageView;
        }

        return null;
    }


    /**
     * 页面宽度所占ViewPager测量宽度的权重比例,默认为1
     */
    @Override
    public float getPageWidth(int position) {
        return (float) 1;
    }


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

    BannerListener bannerListener = null;

    public void setItemClickListener(BannerListener bannerListener) {
        this.bannerListener = bannerListener;
    }


    public interface BannerListener {
        void ItemClick(int postion, GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean data);
    }


    public int ssss(){
        return drawableList.size();
    }

}

收尾:用法

xml中:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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="wrap_content"
    android:background="#ffffff"
    android:orientation="vertical">


    <android.support.v7.widget.CardView
        android:id="@+id/sdsdsds"
        android:layout_width="match_parent"
        android:layout_height="145dp"
        android:layout_below="@+id/app_oneword"
        android:layout_marginBottom="10dp"
        android:layout_marginLeft="12dp"
        android:layout_marginRight="12dp"
        android:layout_marginTop="5dp"
        app:cardCornerRadius="4dp"
        app:cardElevation="2dp">


        <com.watcn.wat.view.banner.AutoScrollViewPager
            android:id="@+id/auto_scroll_viewpager"
            android:layout_width="match_parent"
            android:layout_height="145dp"
            android:clipChildren="false"
            app:change_duration="200" />


        <TextView
            android:layout_width="match_parent"
            android:layout_height="50dp"
            android:layout_gravity="bottom"
            android:background="#33000000"
            android:gravity="left|center"
            android:paddingBottom="5dp"
            android:paddingLeft="8dp"
            android:paddingRight="8dp"
            android:paddingTop="5dp"
            android:text="这个夏季爆品星巴克、喜茶、一点点都在推,为什么你不能卖?"
            android:textColor="#ffffff"
            android:textSize="16sp"
            android:visibility="gone" />


    </android.support.v7.widget.CardView>


    <com.watcn.wat.view.banner.BannerIndicator
        android:id="@+id/indicator"
        android:layout_width="match_parent"
        android:layout_height="17dp"
        android:gravity="center"
        app:change_speech="800"
        app:current_color="#E60012"
        app:pasted_color="#D8D8D8"
        app:slider_align="Center"
        app:slider_height="6dp"
        app:slider_width="10dp" />


</LinearLayout>


java代码中:

ViewPagerAdapter pagerAdapter = new ViewPagerAdapter(topBannerList, getActivity());
autoScrollViewPager.setAdapter(pagerAdapter);
bannerIndicator.setUpWidthViewPager(autoScrollViewPager, topBannerList);
if (topBannerList.size() == 1) {
    autoScrollViewPager.stopAutoPlay();
} else {
    autoScrollViewPager.startAutoPlay();
}
pagerAdapter.setItemClickListener(new ViewPagerAdapter.BannerListener() {
    @Override
    public void ItemClick(int postion, GetTopBannerBena.ResultBean.DataBean.ListBean.BannerBean bannerDatas) {

 

});

 

结束:如果需要切换动画:可以实现ViewPager.PageTransformer接口 如下

public class ZoomOutPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 1f;
    private static final float MIN_ALPHA = 1f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        int pageHeight = view.getHeight();

        if (position < -1) { // [-Infinity,-1)
            // This page is way off-screen to the left.
            view.setAlpha(0);

        } else if (position <= 1) { // [-1,1]
            // Modify the default slide transition to shrink the page as well
            float scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position));
            float vertMargin = pageHeight * (1 - scaleFactor) / 2;
            float horzMargin = pageWidth * (1 - scaleFactor) / 2;
            if (position < 0) {
                view.setTranslationX(horzMargin - vertMargin / 2);
            } else {
                view.setTranslationX(-horzMargin + vertMargin / 2);
            }

            // Scale the page down (between MIN_SCALE and 1)
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

            // Fade the page relative to its size.
            view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));



        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}
### 微信小程序中点击圆形按钮的样式与交互 #### 实现圆形按钮的基础布局 为了在微信小程序中创建一个圆形按钮,通常会使用`<view>`标签并配合CSS样式来设置圆角和尺寸。具体来说: ```css .button-circle { width: 80px; height: 80px; border-radius: 50%; background-color: #1aad19; display: flex; align-items: center; justify-content: center; } ``` 此段代码定义了一个具有固定宽度和高度的正方形区域,并将其四个角落都设为半径等于宽高一半的弧度,从而形成完美的圆形[^1]。 #### 添加点击事件处理逻辑 对于任何类型的按钮,在用户触发点击操作时都需要有相应的响应机制。这可以通过绑定tap事件到目标元素上来完成。下面是一个简单的例子展示如何向上述定义好的圆形按钮添加点击功能: ```html <view class="button-circle" bindtap="onCircleButtonClick"> Click Me </view> ``` 当用户触碰这个视图内的任意位置时就会调用名为`onCircleButtonClick`的方法。 #### JavaScript中的事件处理器函数 接下来是在对应的Page对象里编写实际执行的任务。这里假设希望每次按下按钮之后改变其背景颜色作为反馈: ```javascript Page({ onCircleButtonClick() { this.setData({ 'buttonStyle.backgroundColor': '#3cc51f' }); } }) ``` 这段脚本展示了怎样修改WXML文件里的数据属性以达到视觉上的变化效果。注意这里的`setData()`方法用于安全地更新界面状态而不会引起不必要的重绘开销。 #### 动画增强用户体验 为了让应用更加生动有趣,还可以考虑加入一些过渡动画。比如让按钮被按下的瞬间缩小再恢复原状,这样能提供更好的互动体验感。可以借助于`animation` API轻松实现这一点: ```javascript const animation = wx.createAnimation({ duration: 200, timingFunction: 'ease', }) // Inside the event handler... this.animation = animation.export() this.setData({ animation: this.animation }) // Then apply it to your button style. <button class="animated-button" animation="{{animation}}"> Animate Me! </button> // In CSS, define keyframes or use predefined classes from libraries like animate.css. .animated-button { /* ... */ } @keyframes scaleDownUp { 0% { transform: scale(1); } 50% { transform: scale(.9); } 100% { transform: scale(1); } } ``` 以上就是关于如何在微信小程序内设计可点击的圆形按钮及其基本交互行为的一个概述。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值