Android视图绘画与属性动画

转载至我的个人博客:自定义视图中绘制一个图形

PointF

用于保存两个浮点坐标x,y

float x,y;
PointF location
...
location=new PointF(x,y)

location=new PointF();
location.set(x,y);

Paint

存储绘制信息,决定如何绘制

...
boxPaint=new Paint();
boxPaint.setColor(Color.RED);
backgrounPaint=new Paint();
backgrounPaint.setColor(Color.BLACK);
canvas.drawPaint(backgrounPaint);
canvas.drawRect(left,top,right,bottom,boxPaint);

Canvas

拥有需要的所有绘制操作

....
@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //绘制自定义视图的背景色
    canvas.drawPaint(backgrounPaint);
    for(Boxer boxer:boxers){
        float left=Math.min(boxer.getOrigiin().x,boxer.getCurrent().x);
        float right=Math.max(boxer.getOrigiin().x,boxer.getCurrent().x);
        float top=Math.min(boxer.getOrigiin().y,boxer.getCurrent().y);
        float bottom=Math.max(boxer.getOrigiin().y,boxer.getCurrent().y);
        //画出一个矩形
        canvas.drawRect(left,top,right,bottom,boxPaint);
    }
}

实例:绘制一个矩形

Boxer.class

import android.graphics.PointF;
public class Boxer {
    private PointF origiin;
    private PointF current;
    public Boxer(PointF origiin){
        this.origiin=origiin;
        this.current=origiin;
    }
    public void setCurrent(PointF current){
        this.current=current;
    }
    public PointF getCurrent() {
        return current;
    }
    public PointF getOrigiin() {
        return origiin;
    }
}

BoxVieWer.class

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PointF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class BoxVieWer extends View {
    private static final String TAG=BoxVieWer.class.getSimpleName();
    private Boxer boxer;
    private List<Boxer> boxers;
    private Paint boxPaint;
    private Paint backgrounPaint;
    public BoxVieWer(Context context) {
        super(context);
    }
    public BoxVieWer(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        boxers=new ArrayList<>();
        boxPaint=new Paint();
        boxPaint.setColor(Color.RED);
        backgrounPaint=new Paint();
        backgrounPaint.setColor(Color.BLACK);
    }
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        PointF pointF=new PointF(event.getX(),event.getY());
        switch(event.getAction()){
            case MotionEvent.ACTION_DOWN:
                boxer=new Boxer(pointF);
                boxers.add(boxer);
                break;
            case MotionEvent.ACTION_MOVE:
                if(boxer!=null){
                    boxer.setCurrent(pointF);
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                boxer=null;
                break;
            case MotionEvent.ACTION_CANCEL:
                boxer=null;
                break;

        }
        return true;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawPaint(backgrounPaint);
        for(Boxer boxer:boxers){
            float left=Math.min(boxer.getOrigiin().x,boxer.getCurrent().x);;
            float right=Math.max(boxer.getOrigiin().x,boxer.getCurrent().x);
            float top=Math.min(boxer.getOrigiin().y,boxer.getCurrent().y);
            float bottom=Math.max(boxer.getOrigiin().y,boxer.getCurrent().y);
            canvas.drawRect(left,top,right,bottom,boxPaint);
        }
    }
}

ViewerActivity.class

import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import io.githubs.grooters.luffy.R;
public class ViewerActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.view_drawer);
    }
}

view_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <luffy_viewer.BoxVieWer
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Drawable

Selector

<?xml version="1.0" encoding="utf-8" ?>

    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!-- 默认时的背景图片-->
        <item android:drawable="@drawable/pic1" />
        <!-- 没有焦点时的背景图片-->
        <item android:state_window_focused="false" android:drawable="@drawable/pic1" />
        <!-- 非触摸模式下获得焦点并单击时的背景图片-->
        <item android:state_focused="true" android:state_pressed="true"
            android:drawable="@drawable/pic2" />
        <!-- 触摸模式下单击时的背景图片-->
        <item android:state_focused="false" android:state_pressed="true"
            android:drawable="@drawable/pic3" />
        <!--选中时的图片背景-->
        <item android:state_selected="true" android:drawable="@drawable/pic4" />
        <!--获得焦点时的图片背景-->
        <item android:state_focused="true" android:drawable="@drawable/pic5" />
    </selector>

Shape

  • <?xml version="1.0" encoding="utf-8"?>
    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval"
        android:useLevel="false">
        <stroke
            android:color="@color/colorAccent"
            android:width="1dp"/>
        <size
            android:width="20dp"
            android:height="20dp"/>
    </shape>

  • 矩形
  •     android:shape="rectangle"

  • 线
  •     android:shape="line"

  • 实心
  •     <solid android:color="@color/colorAccent"/>

    Selector与Shape结合使用

    以下代码摘抄自互联网

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <!--第一种方法-->
        <!--<item android:drawable="@drawable/shape_border_press" android:state_pressed="true" />-->
        <!--<item android:drawable="@drawable/shape_border_nor" android:state_window_focused="false"/>-->
        <!--第二种方法-->
        <!--默认情况下是一个带圆角,白色背景,蓝色边框的矩形-->
        <item android:state_window_focused="false">
            <shape android:shape="rectangle">
                <!-- 圆角 -->
                <corners android:radius="5dp" />
                <!--填充颜色为白色-->
                <solid android:color="@color/white" />
                <!-- 描边 -->
                <stroke android:width="1dp" android:color="@color/blue" />
            </shape>
        </item>
        <!--单击时是一个带圆角,白色背景,绿色边框的矩形-->
        <item android:state_pressed="true">
            <shape android:shape="rectangle">
                <!--圆角-->
                <corners android:radius="5dp" />
                <!--填充颜色为白色-->
                <solid android:color="@color/white" />
                <!--描边-->
                <stroke android:width="1dp" android:color="@color/green" />
            </shape>
        </item>
    </selector>

    属性动画

    ObjectAnimator

  • onFloat
  • //从sunStart移动到skyHeight
    ObjectAnimator.ofFloat(sun,"Y",sunStart,skyHeight);
    
    //从当前位置向下移动200,回到初始位置再向上移动100
    ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(sun, "Y", 0, 200, -100,0);

  • setDuration
  • 设置动画时间

    objectAnimator.setDuration(5000);

    eg:

    ObjectAnimator objectAnimator=ObjectAnimator.ofFloat(sun,"y",sunStart,skyHeight).setDuration(2000);
    objectAnimator.start();

    注意:

    在OnCreate()objectAnimator.start();是无效的,因为在OnCreate()中AnimationDrawable还没有完全的与ImageView绑定

    TimeInterpolator

    //由慢变快
    objectAnimator.setInterpolator(new  AccelerateInterpolator());
    //由快变慢
    objectAnimator.setInterpolator(new  DecelerateInterpolator());

    颜色渐变

    int first=getResources().getColor(R.color.colorPrimary,getTheme());
    int second=getResources().getColor(R.color.colorAccent,getTheme());
    int last=getResources().getColor(R.color.black,getTheme());
    ObjectAnimator skyAnimation = ObjectAnimator.ofInt(sky,"backgroundColor",first,second,last);
    skyAnimation.setDuration(5000);
    skyAnimation.setEvaluator(new ArgbEvaluator());
    skyAnimation.start();

    AnimatorSet

    可将动画放在一起播放动画集

    AnimatorSet set=new AnimatorSet();
    set.play(firstAnimation).with(nextAnimation).before(lastAnimation);
    set.start();

    state list AnimatorSet

    使按钮按下和松开具有浮动效果,改变z值

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_pressed="true">
            <objectAnimator
                android:propertyName="translationZ"
                android:duration="100"
                android:valueTo="10dp"
                android:valueType="floatType"/>
        </item>
        <item android:state_pressed="false">
            <objectAnimator
                android:propertyName="translationZ"
                android:duration="100"
                android:valueTo="0dp"
                android:valueType="floatType"/>
        </item>
    </selector>

    将以上xml文件放入animator文件夹

    <Button
        android:id="@+id/button_animation"
        android:stateListAnimator="@animator/button_animator"
        android:elevation="2dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>

    然后通过android:stateListAnimator为组件设置动画

    circular revel

    将View像墨滴一样舒展开来

    @Override
    public void onClick(View view) {
        // 获取FloatingActionButton的中心点的坐标
        int centerX = (view.getLeft() + view.getRight()) / 2;
        int centerY = (view.getTop() + view.getBottom()) / 2;
        Log.i(TAG,"centerX:"+centerX);
        // 获取扩散的半径
        float finalRadius = (float) Math.hypot((double) centerX, (double) centerY);
        // 定义揭露动画
        Animator mCircularReveal = ViewAnimationUtils.createCircularReveal(revelView, centerX, centerY, 0, finalRadius);
        // 设置动画持续时间,并开始动画
        mCircularReveal.setDuration(4000).start();
    }

    其中view为触发组件,revelView为需要揭露出来地新地View,Math.hypot勾股定理求斜边

    shared element transition

    共享元素交换,又称为hero transaction,可实现点击列表中的一张图片,令它以动画形式独立显示在一个新的activity/fragment中

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS);
        setContentView(R.layout.activity_animationer);
        final ImageView sun=findViewById(R.id.sunImage);
        Button tranButton=findViewById(R.id.button_animation);
        tranButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent=new Intent(AnimatioNer.this,ImagerActivity.class);
                ViewCompat.setTransitionName(sun,"image");
                ActivityOptionsCompat optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(AnimatioNer.this,sun,"image");
                AnimatioNer.this.startActivity(intent,optionsCompat.toBundle());
            }
        });
    }

    getWindow().requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)

    必须写在setContentView前

    ViewCompat.setTransitionName(View view, String transictionName )

    view为需要共享的资源,这里是图片sun,transictionName的字符串要和布局(原布局和共享布局)中组件transitionName属性值一样,eg:

    <ImageView
        android:id="@+id/sunImage"
        android:layout_gravity="center"
        android:background="@drawable/sun"
        android:transitionName="image"
        android:layout_width="50dp"
        android:layout_height="50dp"/>

    由于共享布局是共享主布局的sunImage图片,所以共享布局中也必须由图片控件,并带有transitionName=”image”属性

    optionsCompat=ActivityOptionsCompat.makeSceneTransitionAnimation(Activity activity,View view,String transictionName)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值