自定义视角滚动(利用HorizontalScrollView)

本文介绍了如何使用ViewGroup的API实现视觉效果,通过在初始化时启用静态转换,并提供了一个封装在HorizontalScrollView内的自定义布局ScrollContentView.java的示例。在目标SDK为11及以上的ScrollActivity中,需要禁用硬件加速来达到预期效果。

ViewGroup 中的 API 提供了应用视觉效果的简单方法,如:旋转、缩放、透明度,且不必依靠动画。

在初始化的过程中调用 setStaticTransformationsEnabled(true),,可以启用任何 ViewGroup 的静态转换。


上面的效果可以用一个封装在 HorizontalScrollView 的自定义布局。


自定义的 ScrollContentView.java :

package com.crazy.changedview;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.Transformation;
import android.widget.HorizontalScrollView;
import android.widget.LinearLayout;

public class ScrollContentView extends LinearLayout {

    /* 缩放比例 */
    private static final float SCALE_FACTOR = 0.7f;

    /* 变换的中心,(0, 0)是左上, (1, 1)是右下。当前设置的是中间(0.5, 0.5) */
    private static final float ANCHOR_X = 0.5f;
    private static final float ANCHOR_Y = 0.5F;

    public ScrollContentView(Context context) {
        super(context);
        init();
    }

    public ScrollContentView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public ScrollContentView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        // 启动静态变换,这样对于每个视图都会调用 getChildStaticTransformation()
        setStaticTransformationsEnabled(true);
    }

    /**
     * 计算屏幕坐标内所有视图的当前位置
     */
    private int getViewCenter(View view){
        int[] childCoords = new int[2];
        view.getLocationOnScreen(childCoords);
        int childCenter = childCoords[0] + (view.getWidth() / 2);

        return childCenter;
    }

    @Override
    protected boolean getChildStaticTransformation(View child, Transformation t) {
        HorizontalScrollView scrollView = null;
        if (getParent() instanceof HorizontalScrollView) {
            scrollView = (HorizontalScrollView)getParent();
        }
        if (scrollView == null) {
            return false;
        }

        int childCenter =getViewCenter(child);
        int viewCenter = getViewCenter(scrollView);

        // 计算子视图和父容器中心之间的距离,决定应用的缩放比例
        float delta = Math.min(1.0f, Math.abs(childCenter - viewCenter) / (float)viewCenter);

        // 设置最小缩放比例为0.4
        float scale = Math.max(0.4f, 1.0f - (SCALE_FACTOR * delta));
        float xTrans = child.getWidth() * ANCHOR_X;
        float yTrans = child.getHeight() * ANCHOR_Y;

        // 清除现有的所有变换
        t.clear();

        // 为子视图设置变换
        t.getMatrix().setScale(scale, scale, xTrans, yTrans);

        return true;
    }
}


在 ScrollActivity 中 如果程序的目标的 SDK 在 11 及以上时,需要禁用硬件加速,可在代码中设置或 AndroidManifest.xml 中设置;

ScrollActivity.java:


package com.crazy.changedview;

import android.os.Build;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.Gravity;
import android.view.View;
import android.widget.HorizontalScrollView;
import android.widget.ImageView;

public class ScrollActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        HorizontalScrollView parentView = new HorizontalScrollView(this);
        ScrollContentView contentView =
                new ScrollContentView(this);

        // 对此视图禁用硬件加速,否则动态调整每个子视图的变换当前无法通过硬件实现
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
            contentView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
        }

        for (int i = 0; i < 20; i++) {
            ImageView imageView = new ImageView(this);
            imageView.setImageResource(R.drawable.x01);
            contentView.addView(imageView);
        }

        contentView.setGravity(Gravity.CENTER);

        // 添加要显示的视图
        parentView.addView(contentView);
        setContentView(parentView);
    }

}

AndroidManifest.xml :


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值